Skip to main content
The design module is the front-end design system — a type: "design" module under modules/<name>/, published as @module/<name> and consumed primarily by the Single Page App. Its src/ ships ready-made building blocks so you compose UI instead of writing ad-hoc markup: components/ (React primitives), hooks/ (presentation hooks), icons/ (SVG sets), fonts/ (bundled web fonts), styles/ (global stylesheets and tokens), and utils/ (class-name helpers). This page walks through using each asset kind. It is not part of the backend pipeline — see the overview for what it is and the structure for how it is laid out.
Exact import paths and component props depend on your skeleton-design source. The examples below are illustrative — always consult the actual components in modules/<name>/src/ for the real API.

Composing components

components/ holds React (.tsx) UI primitives, one folder per grouping that collects its variants — for example button/ contains Button.tsx, ButtonSave.tsx, and friends. There are around fifty: accordion, avatar, badge, button, card, dialog, form, input, select, table, tabs, tooltip, and more. Compose these primitives rather than reinventing markup or duplicating their internals. Import the pieces you need and assemble a screen:
import { Button } from "@module/<name>/components/button";
import { Card } from "@module/<name>/components/card";

export const ProfileCard = ({ name }: { name: string }) => {
  return (
    <Card>
      <Card.Header>
        <Card.Title>{name}</Card.Title>
      </Card.Header>
      <Card.Body>Welcome back to your workspace.</Card.Body>
      <Card.Footer>
        <Button onClick={() => console.log("saved")}>Save changes</Button>
      </Card.Footer>
    </Card>
  );
};
Reach for a purpose-built variant (such as ButtonSave) when one exists instead of re-implementing its behavior on a base Button.

Using hooks

hooks/ provides reusable React hooks for presentation-layer concerns — state, DOM, and events. The set includes useClickOutside, useMobile, useControlledState, and useAutoHeight. Keep data-fetching and domain logic out of these hooks; that work belongs in services. Use useClickOutside to dismiss a transient surface like a dropdown:
import { useRef, useState } from "react";
import { useClickOutside } from "@module/<name>/hooks";

export const Dropdown = () => {
  const [open, setOpen] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  useClickOutside(ref, () => setOpen(false));

  return (
    <div ref={ref}>
      <button onClick={() => setOpen((value) => !value)}>Menu</button>
      {open && <ul>{/* menu items */}</ul>}
    </div>
  );
};
Use useMobile to branch on viewport for responsive behavior:
import { useMobile } from "@module/<name>/hooks";

export const Layout = ({ children }: { children: React.ReactNode }) => {
  const isMobile = useMobile();

  return isMobile ? <Stack>{children}</Stack> : <SplitView>{children}</SplitView>;
};

Using icons

icons/ ships SVG icons organized by variant, category, and size — the path is icons/<variant>/<category>/<size>/<IconName>.tsx. Variants are fill/ and outline/, sizes are sm, md, and lg, and each icon is its own component file (for example icons/fill/accessibility/lg/AccessibilityLiftIcon.tsx). Import the specific icon you need rather than pasting inline SVG into your components.
import { AccessibilityLiftIcon } from "@module/<name>/icons/fill/accessibility/lg/AccessibilityLiftIcon";
import { SearchIcon } from "@module/<name>/icons/outline/interface/sm/SearchIcon";

export const Toolbar = () => {
  return (
    <div>
      <SearchIcon />
      <AccessibilityLiftIcon />
    </div>
  );
};
The size lives in the import path, not in a prop, so pick it by importing from the matching sm/md/lg folder. Choose outline for neutral, interface-level affordances and fill for emphasis or active states, and keep sizes consistent within a control by importing its icons from the same size folder.

Fonts and styles

fonts/ bundles the web fonts (Space Grotesk) with their @font-face declarations. Reference the bundled fonts — never pull from an external font CDN — so typography stays self-contained and offline-safe. styles/ holds the global stylesheets: app.css, brand.css, shape.css, status.css, and typography.css. Import them once at the app entry point and edit them for app-wide tokens, themes, and base styling.
// app entry point (e.g. main.tsx)
import "@module/<name>/fonts/space-grotesk.css";
import "@module/<name>/styles/app.css";
import "@module/<name>/styles/brand.css";
import "@module/<name>/styles/typography.css";
/* fonts/space-grotesk.css — bundled, no external CDN */
@font-face {
  font-family: "Space Grotesk";
  src: url("./space-grotesk.woff2") format("woff2");
  font-weight: 300 700;
  font-display: swap;
}
Change a token in one place — brand.css for colors, typography.css for type scale, shape.css for radii — and every component that reads it updates with it.

Merging class names with cn

utils/ carries front-end helpers: cn (class-name merge) and staleChunk. Use cn to compose conditional and overriding class names cleanly instead of hand-built string concatenation:
import { cn } from "@module/<name>/utils";

export const Tag = ({ active, className }: { active: boolean; className?: string }) => {
  return (
    <span
      className={cn(
        "rounded px-2 py-1",
        active && "bg-brand text-white",
        className,
      )}
    >
      Tag
    </span>
  );
};
Accepting a className prop and merging it with cn lets callers override styling without you forking the component.

Best practices

  • Compose, don’t duplicate. Build screens from existing primitives and their variants; never copy a component’s internals into your own markup.
  • Keep hooks generic. Use hooks for presentation state, DOM, and events only — keep data-fetching and domain logic in services, not in the design module.
  • Use the provided icons and fonts. Pick a fill/outline icon at a standard size; reference the bundled Space Grotesk fonts rather than inline SVG or external CDNs.
  • Centralize tokens in styles. Put colors, type scale, shape, and status tokens in the styles/ files so changes propagate from one place.
  • No business logic here. The design module is presentation only; domain rules and data access live elsewhere in the stack.
  • Merge class names with cn. Accept a className prop and combine it with cn so consumers can extend styling safely.
  • Verify against the source. Import paths and props depend on the skeleton-design source — confirm the real API by reading the components in modules/<name>/src/.