Skip to main content
Skip to main content
design systems|April 2026–Present

DSharp Design System

The shared UI substrate for a multi-product data-modelling platform: three packages, a contract per component, and domain semantics encoded as atoms instead of styling variants.

Design SystemsAI ArchitectureDesign TokensMCPReact
DSharp logo on the opal-and-ivory brand field

Client

DSharp, a Finnish data-modelling platform shipping DSharp Studio, PathFinder, and the new DSharp Scout.

Type

AI-native product design system. Three layered packages, contract-per-component, enforced spacing.

Stack

React 19TypeScript 5Tailwind 4Storybook 10Published to Azure Artifacts

Distribution

Five npm packages, @dsharp/tokens, @dsharp/tokens-css, @dsharp/react, @dsharp/cli, and @dsharp/mcp, on a scoped Azure Artifacts feed. The MCP server exposes component contracts to AI agents; the CLI scaffolds and validates components against them.

Brief

DSharp ships products to a broad customer base in Finland and internationally: DSharp Studio, a model-first desktop app maintained since 2006; PathFinder, its data-discovery sibling; and DSharp Scout, the new web product under active development. Each product had been built by its own team, with its own components, its own spacing, and its own colour tokens. Migrations between them rebuilt the same primitives. Visual polish regressed every release.

The brief was a shared design system. The constraints made it not a standard one. Scout was being built in parallel with the system itself. Studio was being modularised to consume the same components inside its desktop shell. A Windows target sat on the roadmap. And AI generation was expected to be a first-class consumer of the system, not an experiment on the side.

Approach

1. Contracts & guardrails

  • Four files per component
  • Scaffolder, never hand-written
  • Validator pre-push
  • Status lifecycle gates

2. Tokens

  • DTCG JSON as Layer 0
  • Style Dictionary transforms
  • Semantic palettes per mode
  • 14-step space scale

3. Atoms, molecules, organisms

  • Domain semantics as atoms
  • Molecules combine atoms
  • Workbench-shaped organisms
  • CVA variants + Radix primitives

4. Patterns & templates

  • Layout primitives
  • Product workflow templates
  • Headless mechanics, owned visual
  • Rhythmguard closes the gap

Tokens before components

Base layer is platform-agnostic JSON

The first commitment was that the brand, the rhythm, and the semantic palettes had to exist before the first button. The tokens ship as W3C DTCG JSON in @dsharp/tokens with no runtime dependencies; Style Dictionary transforms them into CSS custom properties and typed TypeScript constants for the web in @dsharp/tokens-css. A Windows or mobile target later becomes a sibling transform package, not a fork of the source.

An early lesson came from the logo atom. Its first version bound the mark to a primitive brand token, which flattened it when the surface inverted in dark mode; DTCG primitives, by design, do not theme-switch. The fix was a dedicated semantic alias that resolves per mode, and a rule that travelled with it: brand-as-decoration uses primitives, brand-as-content uses semantics.

Color · primitivesbrand/opal-dark#577164brand/opal-light#aac6bdbrand/ivory#e6ded0brand/rust#9a5635neutral/black#292628surface/raised#f8f8f7Type · DM Sans / DM MonoAaModeling beats decoration.Headings, body, captions, and mono share one type ramp.var(--font-sans) · var(--font-mono)Space · 14-step rhythm--space-14px--space-28px--space-312px--space-416px--space-524px--space-632px--space-748px--space-864px--space-9128px
Six brand primitives, one type ramp, and the 14-step space scale. The scale numbers are the same set Rhythmguard later enforces in lint, so the rhythm in the documentation and the rhythm in the code cannot drift apart.

The medallion problem

Domain vocabulary belongs in the type system

DSharp’s data work is organised around two closed vocabularies. The medallion architecture sorts every table into one of four layers, source, bronze, silver, or gold, depending on how far it has moved from raw ingest. Every concept is one of four archetypes, moment, party, description, or role. These show up in tables, navigation, diagrams, mapping screens, and forty-odd other surfaces.

The shortest path would have been a generic Badge with variant=“bronze”. The longer path we took was LayerBadge, QualityBadge, and ArchetypeBadge as separate atoms with string-literal unions. The type system refuses unknown values, the validator confirms every variant is covered by a story, and downstream AI agents have one authoritative source for what bronze means and where it can appear.

Button · variantsSix variants, one type ramp, one radius scale.PromoteCancelInspectView sourceDrop layerNew conceptPrimarySecondaryGhostLinkDangerIconPrimary + iconButton · sizesHeights snap to the space scale: 28 · 32 · 40.SaveSaveSavesm · 28pxmd · 32pxlg · 40pxButton · statesEvery variant carries the same four states; focus uses the accent token, never the platform default.PromotePromotePromotePromoteDefaultHoverFocusDisabled
Button is the load-bearing atom in any system: six variants, three sizes, four states, all driven from the same tokens. DSharp’s domain semantics, LayerBadge, QualityBadge, ArchetypeBadge, and ModeSwitch, sit alongside as separate atoms with closed string-literal unions rather than variants of a generic Badge.

A contract per component

The file AI agents read

Every component in @dsharp/react ships four files: the React source, a JSON manifest, a markdown spec, and Storybook stories. The manifest is the file built for agents. It declares the component’s tier and group, its variants and slots, the stories that must exist, the tokens it is allowed to reference, and its accessibility-review state. A scaffolder generates all four files pre-wired; the team rule is that no component is ever hand-written.

A validator runs on every push and on every CI build. It enforces parity between the CVA variant definition and the manifest, story coverage for every declared variant, and a status lifecycle that gates promotion: beta requires a Figma URL, stable requires accessibility review. The contract is also what made it possible to add Rhythmguard alongside the system instead of after; once allowed tokens are listed in the manifest, the linter has a closed set to check against.

Alert · warningMapping review required3 columns need confirmation before promotion.Open reviewDismissTabs · contextual navigationDefinitionSourcesLineageMappingsrole="tablist" · roving focus · arrow-key navFormField · label, control, helperLayer*Promote only validated concepts.silverRequires owner sign-off before gold promotion.Table · composing the atomsCONCEPTLAYERQUALITYCustomersilverreviewOrdergoldgoodProductbronzeraw
Molecules combine atoms without inventing a second palette. The table composes LayerBadge and QualityBadge instead of restyling them; the form field uses the same primary accent the button uses; the alert pulls from the same status tokens.

Composition, continued

Organisms encode the work, not the page

Scout is a task-based workbench rather than a CRUD app, which puts more weight on the organism layer than on the templates above it. LayerNav, ConceptCard, Inspector, AIToolbar, MappingGrid, ConceptDiagram, and LineageGraph carry across every modelling surface because they encode the work, not the page. A modelling template assembles a sidebar, a canvas, an inspector, and a toolbar; a refinement template assembles the same parts in a different proportion.

Inside the heavier organisms, the work split is DSharp-owned visual, library-owned mechanics. DataTable wraps TanStack Table; ConceptDiagram and LineageGraph wrap @xyflow/react. The headless libraries handle sorting, virtualisation, node dragging, and edge routing. DSharp owns the typography, the badge composition, the archetype tints, and the focus rules. The split keeps the system small without rebuilding solved problems.

LayerNav · medallion sidebarLAYERSSource117 tables117Bronze42 tables42Silver18 tables18Gold6 tables6ConceptCard · archetype tintPARTYCustomerA person or organisation that orders.idPKbinary(32)namestringemailstringsincedate3 relations8,912 rowssilverInspector · contract paneCustomer.contracttier: atom · group: domainvariantsprimary / ghostslotslabel · helperasChildtruea11y.reviewedtruetokens.declared12stories.required5 / 5statusstablefigmaEVr7qLFN...AIToolbar · scoped agent actionsAIClassify columnsSuggest mappingPromote to silverExplain lineage2 runningConceptDiagram · ER canvasPersonpartyidPKintnamestringdobdateMembershipmomentidPKintstartdateenddateProjectdescriptionidPKintcodestringnamestring
Every organism reads the same domain semantics. LayerNav surfaces the medallion layers; ConceptCard tints by archetype; the Inspector renders the manifest the validator and AI agents both read; the ConceptDiagram lays the same archetypes out as an ER canvas. DSharp owns the visual language; library code, TanStack Table and xyflow, owns the interaction mechanics.

Closing the gap

Where the rhythm could still leak

One discipline did not survive the move from tokens to composition. Rhythmguard, the Stylelint plugin built alongside the system, enforces the 14-step space scale in CSS declarations and Tailwind class strings. It rejects off-scale literals on padding, margin, gap, inset, and transform translations, and autofixes to the nearest valid step. The values in the spec sheet and the values in the code stay in agreement.

Stylelint cannot reach JSX inline styles or Tailwind arbitrary brackets, so spacing could still leak through composition. The answer was a small set of layout primitives, Stack, Row, Grid, and Container, that take space-scale tokens as props rather than arbitrary numbers. With the lint rule on the styling side and the primitives on the composition side, the rhythm has no path left to drift.

112+ components

Across five tiers: atoms, molecules, organisms, patterns, templates. Each under the same four-file contract.

5 packages

@dsharp/tokens, @dsharp/tokens-css, @dsharp/react, @dsharp/cli, and @dsharp/mcp. Published on a project-scoped Azure Artifacts feed.

2 consumer apps

Scout renders organisms from @dsharp/react in its UI shell. Studio consumes the same package inside its desktop surface. PathFinder is porting in, view by view.

0.1.0 -> 0.59.0

First packaged release shipped April 2026.

Interested in working together?

Let's discuss how design systems, AI and thoughtful UX can elevate your product.