@glamcor/dna-ui
v0.3.3
Published
DNA design system: tokens, components, icons and formatters. The code behind the DNA UI Book.
Maintainers
Readme
@glamcor/dna-ui
The DNA design system as code: tokens, components, icons and formatters. It is the code behind The DNA UI Book (dna-docs/DNA-UI-SPEC.md). Every DNA app uses it, so the platform looks like one product.
- Rules: the Book, and above it
tasks/ui-audit/decisions.mdin the DNA workspace. - Live reference: run
npm run showcaseand openshowcase/index.html. It renders every component with the package itself.
Install
npm install @glamcor/dna-uiPeer dependencies: react and react-dom 18 or 19.
Set up an app (Book chapter 2)
The root layout (src/app/layout.tsx):
import { DM_Sans, JetBrains_Mono } from 'next/font/google'
import { DnaProvider } from '@glamcor/dna-ui'
import '@glamcor/dna-ui/tokens.css'
import '@glamcor/dna-ui/components.css'
import './globals.css'
const dmSans = DM_Sans({ subsets: ['latin'], weight: ['400', '500', '600', '700'], variable: '--font-dm-sans' })
const mono = JetBrains_Mono({ subsets: ['latin'], weight: ['400', '500', '600', '700'], variable: '--font-jetbrains' })
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={`${dmSans.variable} ${mono.variable}`}>
<body><DnaProvider>{children}</DnaProvider></body>
</html>
)
}Then use the components:
import { Button, Icon, Drawer, useConfirm, useToast, fmtMoney } from '@glamcor/dna-ui'What's in the package (the Book says when to use each):
| Area | Components |
|---|---|
| Buttons | Button, IconButton, CloseButton, BackButton, CopyButton |
| Fields | Field, FieldGroup, Input, PasswordInput, Select, Combobox, Textarea, SearchInput, Checkbox, Radio, Switch |
| Layout | FilterBar, Stats, Stat, ResultCount, Total, InfoGrid, InfoCell, Breadcrumb, Tree, PublicCard |
| Navigation in a page | Tabs (buttons or links), Segmented, Steps, MenuButton |
| Overlays | Drawer, Modal, InlineForm, useConfirm, useToast (from DnaProvider) |
| Status | Badge, StatusBadge, Dot, TierBadge, Banner, Progress, Spinner, LoadingState, SkeletonRows, EmptyState, ErrorState |
| People | Avatar, AvatarGroup |
| Other | Icon, CodeBlock, SortHeader, RecordLink, formatters (fmtMoney, fmtDate, …) |
Server components. Importing the package index from a server component works. Components with state carry 'use client'. These render on the server as they are: Progress, Steps (without onSelect), Breadcrumb and link Tabs (with as={Link}), Avatar, InfoCell (including copy), Banner (without onDismiss), Field and FieldGroup around a client control, PublicCard.
CSS Modules reuse the global classes with composes:
.save { composes: dna-btn dna-btn-primary from global; }Check an app: dna-ui-check
This finds code that breaks the Book's hard rules:
- icon libraries (imports, and dependencies in package.json)
- MUI
- Tailwind classes
- pasted SVGs
- emoji
- text characters used as icons (
× ✓ ▼ →), also written as entities (×,✕) or escapes ('\u00d7', CSS'\2192'). An arrow inside a sentence is fine ("Draft → Posted"); an arrow at the edge of a label is not ("Next →"). A × touching a number is a multiplier ("2.5×") - literal font names
- raw colors
confirm(),alert()andprompt()calls (not the words inside strings or comments)- page
<h1>titles
It reads CSS files, and the CSS inside code files too: <style jsx>, <style>{…}</style> and styled-jsx css templates.
npx dna-ui-check # scans ./src, or the whole repo when src has no code
npx dna-ui-check --summary # counts per rule
npx dna-ui-check --json # for scriptsAdd it to the app's scripts as "lint:ui": "dna-ui-check". It exits with code 1 when it finds a problem, so it can gate CI.
Approved exceptions (Book chapter 20):
One line: a comment containing
dna-ui-ignore: <reason>on that line or the line above it.Whole areas: a
dna-ui-check.config.jsonin the app root:{ "ignore": ["src/app/(storefront)/**", "src/lib/vendor"], "rules": { "inline-svg": "off" } }A pattern with
*is a glob (**/matches any folders, or none). A plain path skips that file or folder. Paths are relative to the app root.Always skipped:
node_modules,.next,dist,build,out,coverage,public, and any folder namedgeneratedor__generated__.
Icons
- The registry is in
src/icons/registry.ts. It holds 108 icons: 106 approved by Erik on 2026-10-26, plusheartandbatteryon 2026-10-31. - Each drawing was copied once from Lucide (ISC license, see
LICENSE-LUCIDE), so the package has no icon library dependency. - A new icon needs Erik's approval. Once approved:
- Add the DNA name and its Lucide source name to
MAPinscripts/build-icons.mjs. - Get the
[email protected]icons folder. - Run
npm run icons -- <path to lucide-static>/icons. - Add the icon to the registry table in Book §5.4.
- Add the DNA name and its Lucide source name to
Mockups
scripts/mockup-kit.mjs gives standalone HTML mockups the real package (Book chapter 21):
node scripts/mockup-kit.mjs head # fonts + <style> with tokens and components
node scripts/mockup-kit.mjs icon --size 14 close # registry SVG markup
node scripts/mockup-kit.mjs icons # every icon nameDevelop
npm install
npm run type-check
npm run lint
npm run check:ui
npm run build # writes dist/
npm run showcase # writes showcase/index.htmlPublish
- Bump
versioninpackage.json, following semver: a new component or icon is a minor bump, a fix is a patch. - Commit and push.
- Run
npm ci, thennpm publish.prepublishOnlybuilds first, andpublishConfigmakes the package public. - Bump the version in each app.
