zfb
GitHub repository

Type to search...

to open search from anywhere

Directives

Opt-in
Created Jun 24, 2026Takeshi Takatsudo

Register :::name / ::name / :name directive syntax that maps to your own JSX components. Zero names are registered by default — you supply the vocabulary.

The directives feature populates the Core Directives registry from your zfb.config.ts. It maps CommonMark Directives syntax — container (:::name), leaf (::name), and text (:name) — to JSX component calls in compiled MDX.

Zero directive names are registered by default. You choose the vocabulary; zfb emits the JSX.

Enable

zfb.config.ts
import { defineConfig } from "zfb/config";

export default defineConfig({
  markdown: {
    features: {
      directives: {
        note: "Note",
        tip: "Tip",
        warning: "Warning",
      },
    },
  },
});

The value is a map from directive name → component. Each entry can be a short-form string or a full-form DirectiveSpec object (see below).

Short form — bare component name

The simplest entry maps a directive name to a component identifier string. The directive is registered as a container with titleFromLabel: true — the bracketed [label] becomes a title="…" attribute on the emitted JSX element.

zfb.config.ts
export default defineConfig({
  markdown: {
    features: {
      directives: {
        callout: "Callout",
      },
    },
  },
});

Author writes:

:::callout[Heads up]

Body text.

:::

Pipeline emits:

<Callout title="Heads up">
  <p>Body text.</p>
</Callout>

Full form — DirectiveSpec object

Use the full form to control the directive shape (container, leaf, or text) and whether the bracketed label becomes a title attribute.

zfb.config.ts
export default defineConfig({
  markdown: {
    features: {
      directives: {
        // container (default kind), titleFromLabel on
        note: "Note",

        // leaf directive — self-closing, no body
        youtube: {
          component: "Youtube",
          kind: "leaf",
          titleFromLabel: true,
        },

        // text (inline) directive
        kbd: {
          component: "Kbd",
          kind: "text",
          titleFromLabel: false,
        },
      },
    },
  },
});

DirectiveSpec fields:

FieldTypeRequiredDefault
componentstringyes
kind"container" | "leaf" | "text"no"container"
titleFromLabelbooleannotrue

Directive shapes

  • Container:::name[label]::: wraps a multi-paragraph body into a JSX component. Most commonly used for callout-style blocks.

  • Leaf::name[label]{attrs} produces a self-closing component with no children. Used for embeds (video, code playgrounds, etc.).

  • Text:name[label]{attrs} is an inline component, mixed into prose.

Blank-line requirement

Each fence line (:::name and the closing :::) must be separated from surrounding content by blank lines so the Markdown parser treats them as separate paragraphs. Without blank lines the content is not recognised as a directive and a warning diagnostic is emitted at build time.

Registering a directive does not provide a component

directives is framework-agnostic and ships no JSX components. Registering a directive only tells the pipeline to emit <ComponentName> in compiled MDX. You must:

  1. Author the component yourself.

  2. Add it to your project's MDX components map.

  3. Style it with your own CSS.

Casing and verbatim emit

The component identifier you supply ("Note", "Kbd", "Youtube") is emitted verbatim — there is no auto-PascalCasing and no validation. note: "Note" emits <Note>; note: "my-note" emits <my-note> (a DOM element, likely not what you want).

The directive-name key follows the directive grammar [A-Za-z_][A-Za-z0-9_-]*. A key that does not match this pattern will simply never match any :::name in source.

See also

  • Directives registry — the underlying Core primitive (always active, handles parsing).

  • Recipe: Admonitions — a worked example registering note, tip, info, warning, danger, caution, and details with minimal component stubs and CSS.

  • Custom Directives — register directives via the Rust pipeline API.

Revision History

Takeshi TakatsudoCreated: 2026-06-25T05:17:25+09:00Updated: 2026-06-25T05:17:25+09:00

AI Assistant

Ask a question about the documentation.