Structured Markdown components without framework lock-in Contentbit launched a new open-source library that lets developers write structured, validated Markdown components without being locked into a specific JavaScript framework. The tool uses directive blocks inside ordinary Markdown, which are parsed into a source-mapped AST and validated against schemas before rendering in React, static HTML, or plain Markdown. This approach aims to solve content portability and validation issues for human writers, CMSes, and LLMs generating structured content. Structured Markdown components without framework lock-in Write Markdown with validated, structured blocks. Render it anywhere. Built for content written by humans, CMSes, and LLMs. $ pnpm dlx contentbit@latest init or see a complete article /blog/llm-markdown-that-cannot-break/ rendered by the library 01·The idea Markdown in, components out Authors write directive blocks inside ordinary Markdown. The parser builds a source-mapped AST, the registry validates it, and your renderer of choice takes it from there. Below: the actual styled pack rendering live. :::key-metrics- 65% | Hydration- 24h | Cold ferment- 250g | Ball weight- 450°C | Oven temp::: :::tabs::tab{title="Stand mixer"}Dough hook, speed 2, eight minutes. Stop when the dough clears the bowl .::tab{title="By hand"}Fold every 30 minutes, four times. Slower, same gluten.::: :::comparison{left="Fresh yeast" right="Instant"}- Amount | 9g | 3g- Where to buy | Bakeries | Everywhere- Flavor | Slightly richer | Neutral::: :::callout{type="tip" title="Same source, every target"}This panel is the real React pack. Prose runs through react-markdown https://github.com/remarkjs/react-markdown , exactly like your app would wire it.::: Dough hook, speed 2, eight minutes. Stop when the dough clears the bowl . | Fresh yeast | Instant | | |---|---|---| | Amount | 9g | 3g | | Where to buy | Bakeries | Everywhere | | Flavor | Slightly richer | Neutral | 02·The safety net Errors with line numbers, not broken pages Validation runs before rendering: in your editor, your CI, or your agent loop. Diagnostics carry a code, a position, and a fix hint, so an LLM can repair its own output. :::comparison{left="Basic"} - Price | Free ::: broken.md:1:1 error CB PROPS INVALIDcomparison: prop "right" Invalid input: expected string, received undefinedbroken.md:2:1 error CB ROW COLUMNS:::comparison rows require 3 columns label | left | right . Found 2.hint: Format: - label | left | rightbroken.md:1:1 error CB ROW COUNT:::comparison needs at least 2 rows, found 0. 03·The system One definition, every surface No framework lock-in The content is a protocol. Renderers are adapters: React and static HTML today, plain Markdown always. - Price | Free - Price | Free | $12/mo Validation before render Every block has a schema. Bad content fails with file:line:col diagnostics, not broken pages. Dough basics Weigh everything. Volume measures drift by 20%. :::callout{type="tip"} Cold ferment for flavor. ::: Still just Markdown Documents stay readable in any text editor. Strip the renderer and the content still makes sense. ↳ generated from the registry Made for generated content The registry that validates content also writes the authoring instructions for LLMs, so prompts never drift from the rules. components/ └─ content-blocks/ └─ tabs-block.tsx ← yours now shadcn distribution Styled components install as editable source files through a shadcn registry. You own them after install. js const pricingTable = defineBlock { name: 'pricing-table', props: z.object { currency: z.enum 'usd', 'eur' } , content: pipeRows { columns: 'plan', 'price' } , authoring: { useWhen: ... , example }, } Extensible registry A custom block is a name, a zod props schema, a content model, and authoring guidance, in under 20 lines. It validates, renders, and documents itself from that one definition. 04·The generic pack Eight blocks that work in any niche Pick a block. The example is its real authoring guidance from the registry, the same text LLMs get, rendered live by the styled pack. All blocks → /blocks/ :::callout{type="tip" title="Worth knowing"}Always weigh flour — volume measures drift by 20%.::: Use when: Practical advice that prevents a common mistake tip Highlighted note, tip, warning, important, or TLDR box. 05·Styled pack Install the components, own the code The React pack ships through a shadcn registry. Components land in your app as editable source files: Tailwind, your tokens, your rules. $ pnpm dlx shadcn@latest add @contentbit/generic-pack registry: https://contentbit.dev/r/{name}.json