sdocs
v0.0.174
Published
A lightweight documentation tool for Svelte 5 components
Readme
sdocs
A lightweight documentation tool for Svelte 5 components. Discover .sdoc files in your project and get an interactive component explorer with live previews, prop controls, and code highlighting.
Quick Start
# Initialize config
npx sdocs init
# Start dev server
npx sdocs devInstallation
npm install sdocsRequirements: Node 22+, Svelte 5, Vite 6+, @sveltejs/vite-plugin-svelte 5+
Usage
sdocs can be used in two ways: as a standalone CLI tool or embedded in your existing project.
Standalone (CLI)
Run sdocs as its own dev server:
npx sdocs dev # Start dev server with HMR
npx sdocs build # Build a static site — every route prerendered to real HTML
npx sdocs preview # Preview the built site locally
npx sdocs init # Scaffold a sdocs.config.js file
npx sdocs mcp # Serve the sdocs MCP server on stdio (authoring tools for agents)MCP server
sdocs mcp serves an MCP server so agent
tooling works against the real parser and extractor instead of guessing at the
format. Fourteen tools — ten that read, four that write:
| Read | |
|---|---|
| validate_sdoc | parse .sdoc text, return diagnostics |
| get_authoring_guide | the format reference, whole or by section — also on the web as llms.txt |
| get_changelog | this install's changelog, breaking changes first |
| list_docs | the project's docs, their routes, notes, todos, glossary terms and component statuses — and the running sdocs version |
| search_docs | find a page by any name it goes under, or sweep by note type |
| check_docs | compile every stage, validate the site structure, report what breaks |
| check_coverage | which components have a [COMPONENT] preview |
| resolve_visual_target | a stage's preview-only route, for screenshots |
| get_component_api | a component's full extracted API and its @component description |
| scaffold_component_doc | a starter doc from a component's extracted props |
| Write | |
|---|---|
| set_notes | replace a [NOTES] block |
| set_status | set a [COMPONENT]'s lifecycle status |
| set_todos | replace a [TODO] checklist |
| toggle_todo | tick one item |
Each write rewrites the smallest span that will do, so formatting survives, and
refuses any path the project's include globs do not match.
Register it as a stdio server in any MCP
client — e.g. claude mcp add sdocs -- npx -y sdocs mcp — or, while
sdocs dev runs, point a local client at http://localhost:3000/mcp. The
VS Code extension
registers it with the editor automatically. Built sites carry no MCP endpoint.
Embedded in a SvelteKit / Vite Project
Use sdocs as a Vite plugin inside your existing project. This way sdocs runs alongside your app without needing a separate server.
1. Add the Vite plugin
// vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';
import { sdocsPlugin } from 'sdocs/vite';
export default {
plugins: [
sveltekit(),
sdocsPlugin({
include: ['./src/lib/**/*.sdoc'],
css: './src/styles/global.css',
logo: 'My Design System',
})
],
};The plugin discovers .sdoc files and exposes them via a virtual:sdocs module.
2. Create a page that mounts the sdocs app
<!-- src/routes/docs/+page.svelte -->
<script>
import Explorer from 'sdocs/explorer';
import { docs, cssNames, pageModules } from 'virtual:sdocs';
</script>
<Explorer {docs} {cssNames} {pageModules} title="My Design System" />pageModules is not optional: [DOC] and [PAGE] bodies compile to their own
components and are loaded through it, so an Explorer mounted without it renders
those pages blank with no error.
3. Add the virtual module type declaration (optional, for TypeScript)
// src/app.d.ts or any .d.ts file
declare module 'virtual:sdocs' {
import type { DocEntry } from 'sdocs';
export const docs: DocEntry[];
export const cssNames: string[];
export default docs;
}That's it — your docs page lives at /docs inside your existing app.
Writing Docs
A .sdoc file is <script> at the top, entity blocks in the middle, and an
optional <style> at the bottom. Every entity is its own sidebar entry, so
one file can hold several.
Component docs — [SHOWCASE]
<script lang="ts">
import Button from './Button.svelte';
</script>
[SHOWCASE title="Components / Button" description="A flexible button component."]
[COMPONENT component={Button} status="ready" args={{ label: 'Click me', disabled: false }}]
<Button {...args} />
[/COMPONENT]
[EXAMPLE title="With icon"]
<Button><Icon name="settings" /> Settings</Button>
[/EXAMPLE]
[/SHOWCASE][COMPONENT]— a live showcase with interactive controls.component={X}names the previewed component (its props, events, snippets, methods, state, and CSS custom properties are extracted automatically) andargssets the control defaults.statusis optional:draft,wip,review,experimental,readyordeprecated, shown as a glyph on the component's tab. Two or more[COMPONENT]blocks share one tab strip and must sit inside a[COMPONENTS]wrapper.[EXAMPLE]— frozen showcases rendered exactly as written, shown below the preview area. Each needs a uniquetitle.title— slash-separated path for sidebar navigation.- Blocks are UPPERCASE.
[COMPONENT]and[EXAMPLE]are also accepted in lowercase for files written before 0.0.139.
Doc pages — [DOC]
Freeform markdown content with {expression} interpolation and Svelte
component islands; code fences are inert. The table of contents is generated
from the headings.
[DOC title="Docs / Getting Started"]
## Installation
Run `npm install sdocs` and create your first doc file.
[/DOC]Svelte pages — [PAGE]
A page built in plain Svelte, rendered in the docs app's own context — for
landing pages and custom routes. A [PAGE] without a @section/ title
prefix routes at the site root and belongs to no sidebar; point the config's
home at it for a landing page.
<script lang="ts">
import { CodeBlock } from 'sdocs/ui';
</script>
[PAGE title="Welcome" contentX="center" maxWidth="880px"]
<h1>my-library</h1>
<CodeBlock code="npm install -D my-library" lang="bash" />
[/PAGE]Patterns — [PATTERNS]
One composition of several components — a user menu, a signup panel — with the
states it ships in. A [SHOWCASE] with the prop half switched off: no single
component whose API it could extract, so no [COMPONENT], no props panel and
no controls. Everything else is the same.
<script lang="ts">
import Avatar from './Avatar.svelte';
import Menu from './Menu.svelte';
</script>
[PATTERNS title="Patterns / User Menu" description="Avatar, menu and badge."]
[EXAMPLE title="Signed out"]
<Menu>Sign in</Menu>
[/EXAMPLE]
[EXAMPLE title="Signed in"]
<Avatar name="Ada" /> <Menu>Profile · Sign out</Menu>
[/EXAMPLE]
[/PATTERNS]Each example gets its own sidebar entry and route. Reach for [SHOWCASE] when
one component with an API is the subject, and [LAYOUT] when the composition
is a whole page.
Layouts — [LAYOUT]
Full-page component compositions rendered on an isolated stage.
<script lang="ts">
import Card from './Card.svelte';
import Input from './Input.svelte';
import Button from './Button.svelte';
</script>
[LAYOUT title="Patterns / Login Form" padding="24px"]
<Card padding="24px">
<Input label="Email" type="email" />
<Input label="Password" type="password" />
<Button>Sign in</Button>
</Card>
[/LAYOUT]The full language reference lives at gabilungu.github.io/sdocs/language/overview.
Prop Extraction
sdocs automatically extracts from your Svelte components:
| What | Source |
|------|--------|
| Props | $props() destructuring + interface Props {} |
| Events | Callback props (onclick, onchange, etc.) |
| Snippets | Props typed as Snippet or Snippet<[...]> |
| Methods | Exported functions |
| State | Exported $state / $derived values |
| CSS Custom Properties | @cssvar annotations (defaults from var() fallbacks) |
JSDoc comments on props are picked up as descriptions.
Interactive Controls
Each preview gets live controls based on prop types:
| Prop Type | Control |
|-----------|---------|
| string | Text input |
| number | Number input |
| boolean | Checkbox |
| Color (#hex) | Color picker |
| Dimension (16px) | Number + unit |
Configuration
Create sdocs.config.js in your project root (or run npx sdocs init):
/** @type {import('sdocs').SdocsConfig} */
export default {
// Glob pattern(s) to find .sdoc files
include: ['./src/**/*.sdoc'],
// Dev server port
port: 3000,
// Open browser on start
open: true,
// Header title and logo
title: 'My Design System',
// CSS loaded in preview iframes
css: './src/styles/global.css',
// Top-bar sections, each with its own sidebar order
sections: [
{ slug: 'components', title: 'Components', order: ['Button', 'Input'] },
{ slug: 'guides', title: 'Guides' },
],
};Customization Axes
Declare the dimensions your design system varies along, and each gets a control in the top bar:
axes: [
{ id: 'scheme', label: 'Theme', values: ['light', 'dark'] },
{ id: 'density', label: 'Density', values: ['airy', 'compact'] },
{ id: 'palette', label: 'Color', values: ['blue', 'red', 'olive'] },
]The reader's pick lands on every preview, example and layout as a data- attribute — <html data-scheme="dark" data-density="compact"> — and your own CSS gives it meaning:
[data-scheme="dark"] { color-scheme: dark; --color-bg: #0f1115; }
[data-density="compact"] { --space-md: 8px; }sdocs never interprets an axis, so you can declare any dimensions you like. The first value is the default, and picks persist across sessions.
CSS Stylesheet Switching
Provide named stylesheets to let users switch between whole files:
css: {
light: './src/styles/light.css',
dark: './src/styles/dark.css',
}Reach for axes instead when variants multiply — three palettes × two densities is six stylesheets to maintain but two axes to declare, and axes compose where file swaps can't.
Sidebar Ordering
Sidebar order is per section, set by that section's order array. Listed
items come first, in the order given; everything else follows alphabetically,
so there is no wildcard to write:
sections: [
{ slug: 'components', title: 'Components', order: ['Button', 'Input'] },
{ slug: 'guides', title: 'Guides', order: ['Getting Started'] },
]Entities join a section through their title's @slug/ prefix —
title="@components/Forms / Button". An order entry names the route path
relative to its section.
Package Exports
| Export | Description |
|--------|-------------|
| sdocs | Main entry — sdocsPlugin + types |
| sdocs/vite | Vite plugin function |
| sdocs/explorer | Explorer.svelte UI component |
| sdocs/ui | Reusable UI components (Button, Frame, Icon, Control, NavTree, Stack) |
| sdocs/language | The sdoc scanner, parser, and Svelte projection |
| sdocs/grammar/sdoc.tmLanguage.json | TextMate grammar for editors and highlighters |
License
MIT
