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.
<script
src="https://cdn.mojikumi.jp/v1/mojikumi.min.js"
data-target=".entry-content"
data-style="article"
></script>| Attribute | Default | What it does |
|---|---|---|
| data-target | auto | Selector for the body text; auto looks through the containers it knows |
| data-style | article | article, book, or headline |
| data-precision | auto | native, auto, or full |
| data-exclude | none | Extra selectors to leave alone, comma separated |
| data-css | true | Whether to load the bundled stylesheet |
| data-auto | true | Set 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. Four presets ship with it, book, web, editorial and minimal, differing in how tightly they set.
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.
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.
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.
---
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.
<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.
<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.
import rehypeMojikumi from "@mojikumi/rehype";
export default {
rehypePlugins: [
[rehypeMojikumi, { preset: "editorial" }]
]
};09
Choosing a preset
A preset is a set of adjustments taken together. Choose web if you are unsure. Take book where the page should read like a printed one, editorial where headings should break on phrase boundaries, and minimal to close up runs of punctuation and nothing else. Native uses only what the browser provides and never runs the fallback.
| Adjustment | web | book | editorial | minimal | native |
|---|---|---|---|---|---|
| Runs of punctuation | ○ | ○ | ○ | ○ | ○ |
| Line starts | ○ | ○ | ○ | — | ○ |
| Line ends | Conditional | ○ | ○ | — | ○ |
| Japanese with Latin | ○ | ○ | — | — | ○ |
| Paragraph indent | — | 1em | — | — | — |
| Heading phrase breaks | — | — | ○ | — | — |
| JavaScript fallback | ○ | ○ | ○ | ○ | — |
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.
| Value | Behavior | When to use it |
|---|---|---|
| native | Standard CSS only | When no extra JavaScript is wanted |
| auto | Supplies only what is missing | Almost always the right answer |
| full | Always runs the fallback | Testing, 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.
<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.
Mojikumi.start({ target: ".article", style: "book" });
Mojikumi.refresh();
Mojikumi.stop();| Function | What 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.
<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.
<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