Skip to content

React Components

NPM Version

LikeC4 React library is available to embed diagrams into your applications.
Although you can use it directly, consider Vite Plugin or CLI for smoother development experience.

You must have react and react-dom installed.
Add @likec4/core and @likec4/diagram:

npm i @likec4/core @likec4/diagram

LikeC4 React library can be used in two ways.

This is the easiest way to use the library.
Diagram renders inside shadow DOM, already includes all the dependencies and takes care of the styling.

Diagram requires instance of LikeC4Model.Layouted to render.
You need to prepare it and wrap your diagram withLikeC4ModelProvider component.
Below are examples of how to prepare the model:

  • Using CLI codegen
  • Using Source files
  • Using Model Builder

Prepare model with code generation:

Terminal window
likec4 codegen model --outfile ./likec4-model.ts

Then:

import { LikeC4ModelProvider } from '@likec4/diagram/bundle'
// import model from generated file
import { likec4model } from './likec4-model.ts'
function App() {
return (
<LikeC4ModelProvider model={likec4model}>
{/* ... */}
</LikeC4ModelProvider>
)
}
import { LikeC4View, LikeC4ModelProvider } from '@likec4/diagram/bundle'
function App() {
return (
<LikeC4ModelProvider model={likec4model}>
<LikeC4View
viewId="index1"
onNodeClick={(nodeId) => console.log(nodeId)}
/>
{/* Possible to have multiple views */}
<LikeC4View viewId="index2" />
</LikeC4ModelProvider>
)
}

See LikeC4ViewProps for available props.

LikeC4View renders views from your model, and allows exploring in the popup browser. Component works in most use-cases, but if you need more - use ReactLikeC4:

import { ReactLikeC4, LikeC4ModelProvider } from '@likec4/diagram/bundle'
function App() {
const [viewId, setViewId] = useState('index')
return (
<LikeC4ModelProvider model={likec4model}>
<ReactLikeC4
viewId={viewId}
pannable
zoomable={false}
keepAspectRatio
showNavigationButtons
enableDynamicViewWalkthrough={false}
enableElementDetails
enableRelationshipDetails
showDiagramTitle={false}
onNavigateTo={setViewId}
onNodeClick={...}
/>
</LikeC4ModelProvider>
)
}

Available hooks inside LikeC4View or ReactLikeC4:

import {
useLikeC4Model,
useLikeC4Specification,
useLikeC4ViewModel,
useEnabledFeatures,
useCurrentViewId,
// XYFlow hooks
useXYFlow,
useXYStore,
useXYStoreApi,
// Diagram API
useDiagram,
// Select from state
useDiagramContext
} from '@likec4/diagram/bundle'

If you use built-in icons, install @likec4/icons (or use likec4/icons):

import type { ElementIconRenderer } from '@likec4/diagram/bundle'
import { LikeC4ModelProvider, LikeC4View, ReactLikeC4 } from '@likec4/diagram/bundle'
import { lazy, Suspense } from 'react'
// Better to lazy load icons, bundle is quite large at the moment
const Icon = lazy(async () => {
const { IconRenderer } = await import('@likec4/icons/all')
return { default: IconRenderer }
})
const IconRenderer: ElementIconRenderer = (props) => (
<Suspense>
<Icon {...props} />
</Suspense>
)
function App() {
return (
<LikeC4ModelProvider model={likec4model}>
<LikeC4View
viewId="index1"
renderIcon={IconRenderer}
/>
{/* Same for ReactLikeC4 */}
<ReactLikeC4
viewId="index2"
renderIcon={IconRenderer}
/>
</LikeC4ModelProvider>
)
}

If you want to use package as a library with your bundler, you have to take care of CSS.

Library uses Mantine. If you already use it and have MantineProvider on the scope - LikeC4 diagramr will use it. Otherwise, it will wrap itself with MantineProvider.
Even if you are not using Mantine in your app, its styles are required for the diagrams to work (don’t worry, Mantine is tree-shakable).

Here are the options:

  1. Import all styles

    @import '@likec4/diagram/styles.css'

    This includes all styles, including Mantine styles.

  2. If you are using Mantine

    @layer reset, base, mantine, xyflow, tokens, recipes, utilities;
    @import "@mantine/core/styles.layer.css";
    @import "@likec4/diagram/styles-min.css";
  3. Font.
    LikeC4Diagram uses IBM Plex Sans by default.
    You can bundle it, or import from fontsource, any other CDN or:

    @import '@likec4/diagram/styles-font.css'

    You can override the font, this is explained later.

Check PandaCSS docs for full setup instructions.
LikeC4 provides preset.

npm i @likec4/styles

Configure your panda.config.ts:

import likec4preset from '@likec4/styles/preset'
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
include: [
'src/**/*.{ts,tsx}',
// Include likec4 diagram source code to get the styles
'./node_modules/@likec4/diagram/panda.buildinfo.json',
],
importMap: [
'@likec4/styles',
],
presets: [
likec4preset,
],
theme: {
extend: {
// Here you can override/extend the theme
},
},
})

You global CSS should look like this:

@layer reset, base, mantine, xyflow, tokens, recipes, utilities;
@import "@mantine/core/styles.layer.css";
@import "@likec4/diagram/styles-xyflow.css";
@import "@likec4/diagram/styles-font.css";

Same as ReactLikeC4, but import from @likec4/diagram and you have to provide instance of DiagramView:

import { LikeC4Diagram, LikeC4ModelProvider, useLikeC4ViewModel } from '@likec4/diagram'
function LikeC4View({viewId}: {viewId: string}) {
const view = useLikeC4ViewModel(viewId)
if (!view) {
return <>View not found</>
}
return (
<LikeC4Diagram
view={view.$view}
readOnly
pannable
zoomable={false}
keepAspectRatio
showNavigationButtons
enableDynamicViewWalkthrough={false}
enableElementDetails
enableRelationshipDetails
showDiagramTitle={false}
/>
)
}
function App() {
return (
<LikeC4ModelProvider model={likec4model}>
<LikeC4View viewId="index" />
</LikeC4ModelProvider>
)
}

You can render any component inside LikeC4Diagram
(or LikeC4View/ReactLikeC4 if you are using bundle):

import { LikeC4Diagram, LikeC4ModelProvider } from '@likec4/diagram'
import { Panel, ViewportPortal } from '@xyflow/react'
function App() {
return (
<LikeC4Diagram>
<YourComponent />
{/* You can use components from xyflow */}
<Panel position="top">
<p>Your component as a panel</p>
<a href="https://reactflow.dev/examples">Check examples</a>
</Panel>
<ViewportPortal>
<div
style={{
transform: 'translate(100px, 100px)',
position: 'absolute',
}}>
This div is positioned at [100, 100] on the diagram canvas
</div>
</ViewportPortal>
</LikeC4Diagram>
)
}

LikeC4Diagram can use custom node renderers.
Compose custom nodes renderers using primitives from @likec4/diagram/custom
(or @likec4/diagram/bundle/custom for the bundled version).
See customNodes.tsx for examples.

import { LikeC4Diagram } from '@likec4/diagram'
import {
ElementActions,
ElementDetailsButtonWithHandler,
elementNode,
ElementNodeContainer,
ElementShape,
ElementTitle,
ElementToolbar,
IfNotReadOnly,
} from '@likec4/diagram/custom'
import { IconPlus } from '@tabler/icons-react'
const customNodes = {
element: elementNode(({ nodeProps, nodeModel }) => (
<ElementNodeContainer nodeProps={nodeProps}>
<ElementShape {...nodeProps} />
<ElementTitle {...nodeProps} />
{/* Add extra buttons */}
<ElementActions
{...nodeProps}
extraButtons={[
{
key: 'plus',
icon: <IconPlus />,
onClick: () => console.log('extra'),
},
]}
/>
{/* Add extra info */}
<div style={{ position: 'absolute', bottom: 0 }}>
{nodeModel.element.getMetadata('your-attr')}
</div>
</ElementNodeContainer>
)),
}
function App() {
return (
<LikeC4Diagram
view={view}
renderNodes={customNodes}
/>
)
}

You can also use hooks to access the model and diagram API.

LikeC4Diagram uses PandaCSS for styling. You can use it to customize the styles.

TODO: add example