1. Scaffold the site and add LikeC4
This guide reproduces the site you are reading: a Docusaurus site that renders LikeC4 architecture diagrams, FINOS CALM models, and Slidev decks, deployed to GitHub Pages.
:::info Versions
Written against Docusaurus 3.10, React 19, LikeC4 1.59, CALM CLI 1.59,
and Slidev 52. Newer versions may differ — the APIs below are what these
versions actually expose.
:::
Scaffold Docusaurus
npx create-docusaurus@latest workspaces/docusaurus classic --typescript
cd workspaces/docusaurus
npm start
This gives you the classic template (blog + docs + homepage) in TypeScript.
Add LikeC4
Install the diagram runtime and the CLI (for code generation):
npm install @likec4/core @likec4/diagram
npm install --save-dev likec4
Create a model at likec4/model.c4:
specification {
element actor { style { shape person } }
element system
element component
element database { style { shape cylinder } }
}
model {
customer = actor 'Customer'
website = system 'Website' {
// Built-in icon; rendered by the renderIcon function below.
style { icon tech:docusaurus }
ui = component 'Web UI'
api = component 'Content API'
store = database 'Content Store'
ui -> api 'requests content'
api -> store 'reads/writes'
}
customer -> website.ui 'browses'
}
views {
view index {
title 'System Context'
include *
}
// Give views an explicit id (view <id> of <element>), otherwise LikeC4
// auto-generates ids like `view_xxxxx` that are awkward to reference.
view website of website {
title 'Website — Containers'
include website, website.*, customer
autoLayout LeftRight
}
}
Generate the model
LikeC4 compiles the DSL into a TypeScript model your components import. Add a
script to package.json:
{
"scripts": {
"likec4:codegen": "likec4 codegen model ./likec4 --use-core-package --outfile ./src/likec4/likec4-model.ts"
}
}
Run npm run likec4:codegen to produce src/likec4/likec4-model.ts.
The React component
Diagrams use browser APIs, so render them client-side only with
<BrowserOnly>. Two gotchas that cost real time:
- The model is passed to
LikeC4ModelProvidervia thelikec4modelprop (notmodel). - Import from
@likec4/diagram(the/bundleentry the online docs mention does not exist in1.59), and import styles yourself (next step).
Create src/components/LikeC4/index.tsx:
import React from 'react';
import BrowserOnly from '@docusaurus/BrowserOnly';
export default function LikeC4({
viewId,
height = 480,
}: {
viewId: string;
height?: number | string;
}) {
return (
<BrowserOnly fallback={<div style={{ height }} />}>
{() => {
const { LikeC4ModelProvider, ReactLikeC4 } = require('@likec4/diagram');
const { likec4model } = require('@site/src/likec4/likec4-model');
// Import only the single icon you use. Importing the whole
// @likec4/icons bundle crashes the production bundler.
const DocusaurusIcon = require('@likec4/icons/tech/docusaurus').default;
const renderIcon = ({ node }: { node: { icon?: string | null } }) =>
node.icon === 'tech:docusaurus' ? <DocusaurusIcon /> : null;
return (
<div style={{ height, width: '100%' }}>
<LikeC4ModelProvider likec4model={likec4model}>
<ReactLikeC4
viewId={viewId}
pannable
zoomable
renderIcon={renderIcon}
/>
</LikeC4ModelProvider>
</div>
);
}}
</BrowserOnly>
);
}
Diagram styles
@likec4/diagram uses Mantine. Add the styles (with the correct CSS layer
order) to src/css/custom.css:
@layer reset, base, mantine, xyflow, tokens, recipes, utilities;
@import '@mantine/core/styles.layer.css';
@import '@likec4/diagram/styles.css';
@import '@likec4/diagram/styles-font.css';
Use it in a page
import LikeC4 from '@site/src/components/LikeC4';
<LikeC4 viewId="index" />
<LikeC4 viewId="website" />