Shared Vue 3 + Tailwind v4 design-system atoms and design tokens for codebar-ag applications, documented in Storybook. One source of truth so every app looks identical.
Live Storybook: https://codebar-ag.github.io/storybook.codebar.ch/ — every atom
and its variants, deployed automatically from main.
Atoms only. This package ships the basic building blocks (button, card, table, badge, form fields, dropdown, icon, list-row, metric, alert…) and the design tokens. Composite, domain-specific "organisms" (billing panels, instance rows, …) live in each consuming app — but they must be assembled only from these atoms, never from raw HTML elements.
The package is published to GitHub Packages. Add an .npmrc to the consuming app:
@codebar-ag:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
npm install @codebar-ag/storybookNote: the package is private; GitHub's npm registry requires authentication to install. Set
GITHUB_TOKENto a GitHub token with theread:packagesscope (a classic PAT works) — locally, in CI, and on deploy targets.
1. Tokens + Tailwind — in your app's app.css:
@import "@codebar-ag/storybook/tokens.css"; /* @theme: colors, type scale, radius */
@import "tailwindcss";
@source "../../node_modules/@codebar-ag/storybook/dist"; /* scan atoms for classes */The @source line is required: Tailwind must scan the compiled atoms so their
utility classes are generated in your app's stylesheet.
2. Register the atoms — in your Vue entry:
import { Flows } from '@codebar-ag/storybook';
createApp(...).use(Flows); // global <Button>, <Card>, <Icon>, …Or import individually:
import { Button, Card, useToast } from '@codebar-ag/storybook';3. Toasts — mount <Toaster /> once near the root, then push() from anywhere:
import { pushToast } from '@codebar-ag/storybook';
pushToast({ message: 'Saved.', type: 'success' });Component-based consistency is the point of this package: every app should look identical because every app is built from the same atoms.
- Check Storybook first. Browse the
live Storybook (or run
npm run devin this package) and searchsrc/index.ts's barrel export before writing any markup for a new screen or feature. - Never re-implement an atom. If this package already ships a
Button,Card,Table,Badge,Modal, form field, dropdown, icon, list-row, metric, or alert, the consuming app must import and use it — not hand-roll an equivalent with raw<button>/<table>/<div>+ Tailwind classes. - Compose, don't fork. If an atom is close but not quite right, extend it via
its existing props/slots/
classoverrides. Don't copy its template into the app and tweak it. - Domain-specific "organisms" (billing panels, instance rows, resource lists, …) stay in the consuming app, but must be assembled only from these atoms, never from raw HTML elements.
Only add a component here when no existing atom (or composition of atoms) can satisfy the need. A new atom must:
- Live in
src/components/as a<script setup>Vue 3 SFC. - Be styled only with token-driven Tailwind utility classes — no
<style>blocks, no@apply, no bespoke CSS. - Ship a
*.stories.tsentry documenting its variants. - Pass
npm run typecheckandnpm run lint. - Be exported from
src/index.ts(and registered on theFlowsplugin if it's a globally-usable atom).
npm install
npm run dev # Storybook on :6006 (the styleguide)
npm run build # library build → dist/ (ESM + types + tokens.css)
npm run build-storybook # static styleguide → storybook-static/
npm run typecheck # vue-tsc
npm run lint- Placeholder names in story fixtures. Real client and person names were
replaced with
Mustermann AG/Max Mustermannplaceholders (andmustermann.*hosts) throughout the Storybook stories. No component or API changes.
- All-mono restored. v1.4.0 switched the UI font to Inter; that is reverted.
The all-mono look (JetBrains Mono everywhere, via
--font-mono) is the brand's visual identity and is intentional. Skip v1.4.0 and upgrade straight to v1.4.1.
- New components — atoms
Avatar,Divider,Kbd,Spinner; moleculesAccordion/AccordionItem,Combobox,InputNumber,PasswordInput,PinInput,Popover,Tabs,Tooltip; organismsDataTable(sortable, selectable, paginated),Drawer,Navbar,Sidebar/SidebarGroup/SidebarItem; layoutsAppShell,AuthLayout,ErrorLayout. - Composables are now part of the public API — overlay/keyboard utilities
(
useFocusTrap,useClickOutside,useEscapeKey,useScrollLock,useListNavigation), form helpers (useFieldA11y,useFormErrors,usePasswordManagerAttrs), data-table helpers (useSort,useSelection,usePagination), plususeControllableanduseRootAttrs. - Helpers —
cxclass combiner andresolveTonewith theTone/LegacyTonetypes. - Storybook — Foundations docs (colors, typography, spacing, radii & shadows, icons), example pages (Auth, Errors, Dashboard), docs + a11y addons, and per-story play functions that run in CI via Playwright.
Non-breaking, but worth knowing when upgrading:
- Tones unified.
Badge/StatusBadgenow use the semantic tonesneutral | info | success | warning | danger;Alertgaineddanger. The old values (gray/blue/green/amber/red, Alert'serror) keep rendering identically viaresolveTone()but log a dev-only deprecation warning and will be removed in the next major. - Dropdown DOM changed. The root moved from
<details>/<summary>to<div><button aria-haspopup="menu">…with full keyboard support (arrows, Home/End, Escape, click-outside). Props and slots are unchanged; only CSS targetingdetails/summaryneeds updating. Optionalv-model:open. - Button gained a
loadingprop (spinner +disabled+aria-busy); the default slot is now wrapped in a layout<span>. - Modal now traps focus, locks page scroll, restores focus on close and
supports
initialFocus; API unchanged. - FileInput supports
v-model(File[]); the previouschange(FileList) emit is retained. It now renders inside the standard control box. Switchis a new alias export forToggle(both names work).- Components moved into
src/components/{atoms,molecules,organisms,layouts}; the public API (src/index.ts) is unchanged. - Storybook story IDs changed with the new
Foundations/Atoms/Molecules/ Organisms/Layouts/Pageshierarchy — deep links into the published styleguide need re-copying. - Bugfix: dismissed toasts were hidden but never removed from the DOM
(
useToastreassigned the array its consumers had captured); they are now spliced in place.
MIT © codebar Solutions AG