Adding a component to Unovis
Operational checklist. For the conceptual tutorial (data models, SVG vs HTML, transitions) read
packages/website/contributing/guides/adding-a-component.mdx. Before writing anything, open a
similar existing component and copy its shape — e.g. packages/ts/src/components/line (XY) or
packages/ts/src/components/donut (Core).
1. Build the core in packages/ts
Create packages/ts/src/components/<kebab-name>/ (kebab-case dir + files):
config.ts—ConfigInterface(JSDoc each prop, end withDefault: \...`) and aConfigclass with defaults. Extend the right superclass:XYComponentConfig*for XY components,ComponentConfig*` for Core components. Stand-alone components don't extend.index.ts— the component class. ExtendsXYComponentCore/ComponentCore(or stands alone). Declaresstatic selectors = s,static cssVariables = s.variables,config,events, and a_render(customDuration?)(orrender) with clear enter / update / exit D3 selections.style.ts— emotioncssselectors + acssVarDefaultsmap. CSS variables are named--vis-<component>-<selector>-<property>; every color var needs a--vis-dark-...counterpart. Importcss/injectGlobalfrom@/styles/emotion(not@emotion/cssdirectly) so styles respect theglobalThis.UNOVIS_NONCECSP nonce. Exportvariables = getCssVarNames(cssVarDefaults)and callinjectGlobalCssVariables(...).types.ts— component-specific types (optional).modules/— extract long render logic intocall-able helpers (optional).
Match the house style: no semicolons, single quotes, 2-space indent, explicit return types.
2. Export from core
- Add the component (and its public config/types) to
packages/ts/src/components.ts. - If you expose new public types, also export them from
packages/ts/src/types.ts.
3. Register in the shared registry
Add one entry to getComponentList() in packages/shared/integrations/components.ts. This is
the source of truth for the wrapper generators and for commitlint's Component scope.
XY component:
{ name: 'YourComponent', sources: [coreComponentConfigPath, xyComponentConfigPath, '/components/your-component'], dataType: 'Datum[]', angularProvide: 'VisXYComponent' },
Core (single) component:
{ name: 'YourComponent', sources: [coreComponentConfigPath, '/components/your-component'], dataType: 'Datum[]', angularProvide: 'VisCoreComponent' },
Optional fields seen in the file: kebabCaseName (when the auto kebab is wrong, e.g.
TopoJSONMap → topojson-map), elementSuffix, isStandAlone, renderIntoProvidedDomNode,
angularStyles / svelteStyles / vueStyles / solidStyles.
4. Generate the wrappers
For each wrapper package, run generate from its directory (or via filter):
cd packages/react && pnpm generate
cd packages/angular && pnpm generate
cd packages/svelte && pnpm generate
cd packages/vue && pnpm generate
cd packages/solid && pnpm generate
- Never hand-edit generated files (they start with
// !!! This code was automatically generated !!!). If a wrapper looks wrong, fix the core config or the shared TS parser (packages/shared/integrations) and regenerate — don't patch the output. - Barrels: Solid/Svelte/Vue update
src/components.tsautomatically; for React and Angular add the export line topackages/{react,angular}/src/components.tsby hand. Verify every wrapper'ssrc/components.tsincludes your component.
5. Dev example (packages/dev)
Add at least one page under packages/dev/src/examples/<category>/<component>/<example>/index.tsx,
exporting title, subTitle, and a component. Add/extend the component-level
.../<component>/index.tsx group index. Verify with pnpm dev (http://localhost:9500).
6. Gallery example
Follow /add-gallery-example (files in packages/shared/examples/<slug>/ + examples-list.tsx +
light/dark previews).
7. Docs (packages/website)
Add packages/website/docs/<category>/<Name>.mdx (e.g. xy-charts/, misc/). Structure: Basic
Configuration → CSS Variables → Events → Component Props. Use the helpers DocWrapper,
PropsTable, CSSVariables. Verify with pnpm website (http://localhost:9300).
8. Verify & commit
pnpm build:tscompiles;pnpm lintclean; component renders inpnpm dev; wrappers exist in everysrc/components.ts.- Commit with the 4-group convention and open the PR — see
/commitand/open-pr.
Done when: core compiles, a dev page exists, every wrapper exports it, it has a gallery example, and it has a docs page.