Documentation

Start small, add only what you need

Start with one script tag, or with the CSS preset, then add the DOM fallback only where it is still needed. React and MDX follow the same steps, and the rule never changes: the text itself is left alone.

01

Use it from a script tag

On a site with no build step, one script is the whole installation. The stylesheet travels inside the bundle, so there is a single file to load, the tag carries its own settings, and articles that arrive after load are picked up on their own.

HTML
<script
  src="https://cdn.mojikumi.jp/v1/mojikumi.min.js"
  data-target=".entry-content"
  data-style="article"
></script>
AttributeDefaultWhat it does
data-targetautoSelector for the body text; auto looks through the containers it knows
data-styleminimalminimal (restrained), article (justified), or book (a printed page)
data-precisionautonative, auto, or full
data-indentup to the presetfalse for no indent; a length such as 2em also works
data-justifyup to the presetfalse to leave the right edge ragged
data-hangingup to the presettrue to hang line-final stops outside the measure
data-heading-breakup to the presettrue to break headings at phrase boundaries
data-excludenoneExtra selectors to leave alone, comma separated
data-csstrueWhether to load the bundled stylesheet
data-autotrueSet to false and nothing happens until Mojikumi.start() is called

02

Use the CSS on its own

Import the CSS preset, put a class on your body copy, and you are done. Browsers that understand the standard properties start closing up punctuation right away. No build step, no JavaScript. Three presets ship with it, minimal, article and book, differing in how far towards print composition they go.

TSX
import "mojikumi/css";

<article lang="ja" className="mjk mjk-book">
  <p>『Webの日本語』を端正にする</p>
</article>

03

Add the DOM fallback

When browsers without the standard properties should see the same page, add the DOM layer. Runs of punctuation, a bracket landing at the start or end of a line: the positions CSS cannot settle are measured and corrected at runtime. Leave precision on auto and nothing runs where support already exists.

TypeScript
import "mojikumi/css";
import { mojikumi } from "mojikumi";

const instance = mojikumi(".article", {
  preset: "book",
  precision: "auto"
});

04

Use it with React

The server emits ordinary HTML, and any adjustment happens once it reaches the browser. There is a component to wrap with and a hook to attach to an element you already render, so nothing about your layout has to move.

TSX
import { Mojikumi } from "@mojikumi/react";

export function Article({ children }) {
  return (
    <Mojikumi as="article" preset="book">
      {children}
    </Mojikumi>
  );
}

05

Use it with Astro

Astro ships static HTML, so the call goes in a component's script tag: the stylesheet in the frontmatter, the DOM layer on the client. Where a view transition swaps the document, call it again on astro:page-load.

Astro
---
import "mojikumi/css";
---

<article class="article" lang="ja"><slot /></article>

<script>
  import { mojikumi } from "mojikumi";
  mojikumi(".article", { preset: "book" });
</script>

06

Use it with Vue / Nuxt

onMounted only runs in the browser, so what Nuxt renders on the server is your markup untouched. Destroy the instance as the component goes, and nothing it generated outlives it.

Vue
<script setup>
import { onBeforeUnmount, onMounted, ref } from "vue";
import { createMojikumi } from "mojikumi";

const root = ref(null);
let instance;

onMounted(() => {
  instance = createMojikumi({ preset: "book" }).mount(root.value);
});

onBeforeUnmount(() => instance?.destroy());
</script>

<template>
  <article ref="root" lang="ja"><slot /></article>
</template>

07

Use it with SvelteKit

An $effect runs in the browser only, leaving the server-rendered output alone. The function it returns is the teardown, so the instance is destroyed with the component.

Svelte
<script>
  import { createMojikumi } from "mojikumi";

  let root;

  $effect(() => {
    const instance = createMojikumi({ preset: "book" }).mount(root);
    return () => instance.destroy();
  });
</script>

<article bind:this={root} lang="ja"><slot /></article>

08

Use it with Markdown / MDX

Registered as a rehype plugin, the preset applies to the body of every article. The Markdown source stays as written, so authors never have to think about typesetting. Code blocks and math are left out, so runs of symbols are never disturbed.

TypeScript
import rehypeMojikumi from "@mojikumi/rehype";

export default {
  rehypePlugins: [
    [rehypeMojikumi, { preset: "article" }]
  ]
};

09

Choosing a preset

The presets are three steps towards print composition. Minimal is the compromise that standard CSS can reach on its own, and it leaves line ends alone. Article justifies the text and trims the line ends, which is what Mojikumi is for. Book adds the paragraph indent and the hanging punctuation of a printed page. Minimal is the default and article is the one to choose if you are unsure. Trimming a line end needs justification, and justification needs the DOM fallback until browsers ship text-spacing-trim: trim-both, so a page that says nothing is not signed up for that. The retired names web, editorial and native still resolve.

Adjustmentminimalarticlebook
Runs of punctuation○○○
Line starts○○○
Japanese with Latin○○○
Justified—○○
Line endsConditional○○
Paragraph indent——1em
Hanging punctuation——○

09

Choosing the indent and the justification

Whether paragraphs are indented and whether the text is set flush to both edges are decisions about the page rather than about Japanese typography, so they are not fixed by the preset. Leave indent and justify out and the preset decides; set either and it wins, which is how you keep the composition of book while dropping its indent. Setting justify to false also stops line ends being trimmed, since that trim only shows in a justified line.

HTML
<script
  src="https://cdn.mojikumi.jp/v1/mojikumi.min.js"
  data-style="book"
  data-indent="false"
></script>

10

Deferring to the browser

Precision decides how far the standard CSS is trusted before the DOM layer steps in. On auto, Mojikumi measures whether the browser is actually closing up punctuation before deciding, because some implementations accept the syntax and change nothing on screen. That is a measurement, not a support table.

ValueBehaviorWhen to use it
nativeStandard CSS onlyWhen no extra JavaScript is wanted
autoSupplies only what is missingAlmost always the right answer
fullAlways runs the fallbackTesting, or comparing implementations

11

Changing what it applies to

Code, form controls, anything being edited, SVG and MathML are left out without being asked. To exclude a particular passage, mark it with data-no-mojikumi. To exclude a set of them, pass selectors through exclude or data-exclude.

HTML
<span data-no-mojikumi>console.log("日本語")</span>
  • Excluded by default: script, style, code, pre, kbd, samp, textarea, input, select, option, contenteditable, svg, math
  • Any element marked data-no-mojikumi, and everything inside it
  • Any selector added through data-exclude or exclude

12

Driving it from code

Loaded from a script tag, Mojikumi is available as a global. Set data-auto to false and the timing is yours to choose. From npm, the mojikumi package exposes the same behavior through its mojikumi function.

JavaScript
Mojikumi.start({ target: ".article", style: "book" });
Mojikumi.refresh();
Mojikumi.stop();
FunctionWhat it does
start(options)Applies Mojikumi, and keeps applying it to articles added later
refresh()Measures line starts and line ends again
stop()Removes the generated elements, the classes and the stylesheet

13

Pinning a version

What sits behind /v1/ is replaced whenever a fix ships. That is how a pasted tag receives improvements without being pasted again, and it also means our changes reach your site directly. To decide that timing yourself, use the URL with a version in it. Those files are never rewritten, so they are cached for a year.

HTML
<script
  src="https://cdn.mojikumi.jp/0.2.1/mojikumi.min.js"
  data-target=".entry-content"
  data-style="article"
></script>
  • The current release is 0.2.1
  • A pinned URL never updates, so moving to a new release means editing the tag
  • To check that the file itself has not been swapped, generate a hash from it and add an integrity attribute

14

Serving it yourself

If you would rather not use the CDN, the npm package carries the same file. Copy node_modules/mojikumi/dist/mojikumi.browser.js somewhere your site serves it from and point src at that path. Nothing else changes.

HTML
<script src="/assets/mojikumi.min.js" data-style="article"></script>

15

Taking it back out

Delete the script tag, or call stop(), and the page returns to how it was. Because the text is never rewritten, removing Mojikumi leaves nothing behind to clean up.

  • Generated elements and classes are removed, and changed attributes are put back
  • The text was never altered, so nothing lingers in what you have saved
  • If the script fails to load at all, the article still reads

16

Design policy

  • Standard CSS runs first, and where a browser supports it that is the whole story
  • The text is never rewritten, so what gets copied and what is read aloud stay as written
  • As native support grows, the amount of code that loads shrinks on its own
  • Where a font carries no punctuation metrics, nothing is tightened by guesswork

Next step

See it on real sentences

To the Playground