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-stylearticlearticle, book, or headline
data-precisionautonative, auto, or full
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. Four presets ship with it, book, web, editorial and minimal, differing in how tightly they set.

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: "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.

Adjustmentwebbookeditorialminimalnative
Runs of punctuation
Line starts
Line endsConditional
Japanese with Latin
Paragraph indent1em
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.

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