Skip to main content
LisibleDocumentation
Live previewer

Author and publish

MDX components

Add file trees, tabs, steps and hidden content to a page without giving up Markdown simplicity.

MDX is Lisible’s default article format. It keeps all syntax presented in Extended Markdown and allows components inside prose. Every reference below shows complete copyable code, followed immediately by its actual rendering.

Imports

React and Astro components must be imported after frontmatter and before the first content. An import adds no browser JavaScript until its component is used. The github and drawio Markdown directives are provided by the processing pipeline and require no import.

Code

---
title: "My interactive post"
description: "An example using Lisible MDX components."
pubDate: 2026-07-19
---
import { Tabs, Tab } from "@/components/ui/tabs";
import { Steps, Step } from "@/components/ui/steps";
import { Tree } from "@shared/components/ui/file-tree";
import Spoiler from "@/components/Spoiler.astro";
import Diagram from "@shared/components/Diagram.astro";

Rendered output

Imports produce no visible element. They simply make Tree, Tabs, Tab, Steps, Step, Spoiler and Diagram available to the examples that follow.

File tree

Tree displays an interactive file hierarchy shared by all six variants. Folders can be opened independently, files can be selected and the global control expands or collapses every folder. Use it for project structures where a static text tree would hide useful detail.

PropertyTypeDefaultPurpose
elementsTreeViewElement[][]nested files and folders
initialExpandedItemsstring[][]folder IDs open on first render
initialSelectedIdstringabsentinitially highlighted item
indicatorbooleantruebranch connector lines
sort"default", "none" or comparator"default"folders-first natural sorting, source order or custom order
dir"ltr" or "rtl""ltr"text direction
classNamestringemptyextra classes on the container
client:loadAstro directiverequiredenables selection and folder controls

Every element needs a unique id and a name. Set type to file or folder; an item with children is also inferred as a folder. isSelectable: false disables selection while preserving the item in the hierarchy.

In an MDX island, use "default" or "none" for sort because Astro serializes properties across the server/client boundary. A comparator function belongs inside a React wrapper component.

Code

import { Tree } from "@shared/components/ui/file-tree";
<Tree
client:load
initialExpandedItems={["src", "pages"]}
initialSelectedId="home"
elements={[
{
id: "src",
name: "src",
type: "folder",
children: [
{
id: "pages",
name: "pages",
type: "folder",
children: [{ id: "home", name: "HomePage.astro", type: "file" }],
},
{ id: "styles", name: "styles.css", type: "file" },
],
},
{ id: "config", name: "lisible.config.json", type: "file" },
]}
/>

Rendered output

Arborescence

Tabs

Tabs groups alternative content without making the page longer. Use it for equivalent commands, configuration variants or examples in several languages. Each item in tabs maps to one Tab component in the same order.

PropertyTypeRequiredPurpose
tabsstring[]yestab labels and order
labelstringrecommendedaccessible name for the group
defaultTabstringnotab selected on initial load
classNamestringnoextra classes on the container
client:loadAstro directiveyes hereenables clicks and keyboard navigation immediately

Tab accepts MDX content and an optional className property. Keep the number of Tab children equal to the number of labels: panels are matched by position.

Code

import { Tabs, Tab } from "@/components/ui/tabs";
<Tabs
tabs={["bun", "npm", "pnpm"]}
label="Package manager"
defaultTab="npm"
client:load
>
<Tab>
```bash
bun install
bun run dev
```
</Tab>
<Tab>
```bash
npm install
npm run dev
```
</Tab>
<Tab>
```bash
pnpm install
pnpm dev
```
</Tab>
</Tabs>

Rendered output

Terminal window
bun install
bun run dev
Terminal window
npm install
npm run dev
Terminal window
pnpm install
pnpm dev

The component exposes tablist, tab and tabpanel roles. Left and right arrow keys switch tabs, while Home and End reach the first and last. The label should therefore describe the available choice instead of repeating “tabs”.

Steps

Steps presents an ordered procedure with visual numbering and connectors. Each Step represents one coherent action; its title should begin with a verb, and its body can contain paragraphs, lists, links or code blocks.

ComponentPropertyTypeRequiredPurpose
Stepsol attributesHTML attributesnocustomize the ordered list
Steptitlestringyesvisible step heading
Stepli attributesHTML attributesnoidentifier, classes or additional data

This component has no interactive state: do not add a client:* directive. It renders as static HTML.

Code

import { Steps, Step } from "@/components/ui/steps";
<Steps>
<Step title="Create the bilingual pair">
Run `bun run new-post guide --translate` to create both `.mdx` files.
</Step>
<Step title="Import the components">
Put imports after frontmatter and before the first paragraph.
</Step>
<Step title="Validate the result">
- test keyboard use;
- check light and dark themes;
- run the static build.
</Step>
</Steps>

Rendered output

  1. Create the bilingual pair

    Run bun run new-post guide --translate to create both .mdx files.

  2. Import the components

    Put imports after frontmatter and before the first paragraph.

  3. Validate the result

    • test keyboard use;
    • check light and dark themes;
    • run the static build.

Spoiler

Spoiler blurs a short answer until a click or activation with Enter or Space. It accepts only its child content and needs no hydration directive because its behavior is owned by the Astro component.

Code

import Spoiler from "@/components/Spoiler.astro";
The answer is <Spoiler>islands architecture</Spoiler>.

Rendered output

The answer is .

GitHub card

The github directive turns an owner/repository identifier into a clickable card. The link works immediately, then a client-side script enriches the card with the available description, language, stars and forks. No MDX import is required.

AttributeFormatRequiredPurpose
repoowner/repositoryyesGitHub repository to display and link destination

Code

::github{repo="didntchooseaname/lisible-docs"}

Rendered output

Use a single card when the repository is the primary destination. For a reference list, plain links remain faster to scan.

draw.io diagram

The drawio directive loads an SVG export created with draw.io into a viewer with zoom, pan, reset and full-screen controls. Full screen uses the same browser API and viewport-overlay fallback as Mermaid and closes with Escape. The Markdown image nested inside the directive acts as a fallback if loading or script execution fails.

AttributeTypeRequiredPurpose
srcpublic path to an SVGyesexported draw.io file to load
titlestringrecommendedaccessible diagram name

The fallback image’s alternative text must describe the information in the diagram. It should not stop at “diagram” or repeat the filename.

Code

:::drawio{src="/images/demo-ilots.svg" title="Islands pipeline"}
![Pipeline showing content flowing into the six Astro variants](/images/demo-ilots.svg)
:::

Rendered output

Diagram
100%
Rendering diagram...
Scroll to zoom, drag to pan

Pipeline showing content flowing into the six Astro variants

Inline SVG schematics

Diagram inserts a schematic straight into the HTML rather than loading it through <img>. That is what makes it live: an inline SVG inherits the page custom properties, so its strokes follow the accent the reader picks in the header and its surfaces follow the active theme, with no JavaScript and no extra request. An SVG served through <img> stays isolated from the page and cannot do that.

Three schematics ship with the framework: islands, pipeline and tokens. Pass the locale so the labels and the caption match the article.

Code

import Diagram from "@shared/components/Diagram.astro";
<Diagram id="islands" locale="en" />
<Diagram id="pipeline" locale="en" caption="From source file to served page." />

Rendered output

A figure with a caption, sized by aspect ratio so it reserves its space before paint. Add your own by extending the copy map and the drawing branches in shared/components/Diagram.astro.

Choosing hydration

A client:* directive belongs only on a framework component that needs browser JavaScript. Astro components such as Spoiler own their scripts, while purely static components such as Steps need no hydration.

DirectiveActivation timeUse
client:loadon page loadimmediately necessary interaction such as Tabs
client:idlewhen the browser becomes availablenon-critical enhancement
client:visiblenear the visible areainteractive component far below the fold

When unsure, start without a directive: add one only when the framework component contains state, an event or a browser API that must run on the client.

Documentation maintained with LisibleEdit this page ↗

Actions

Search for an API, a command or a concept.