DESIGN.md
Personality: Human, optimistic, lighthearted, reliable, adaptable, fine-crafting.
Design Principles: Solve human problems, enhance human ability, trustworthy, transparent, holistic, predictive.
Error Messages:
Feedback Messages:
Labels and Buttons:
Links:
For domain terminology (Project, Task, Annotation, etc.), see terminology.mdc cursor rule.
WCAG 2.1 Level AA compliance required.
Keyboard Navigation:
Visual:
Structure:
aria-describedbyLocation: web/libs/ui/src/tokens/tokens.prefix.css
Always use semantic tokens instead of numeric values:
| Category | ✅ Use Semantic | ❌ Don't Use Numeric |
|---|---|---|
| Spacing | p-tight, m-base, gap-wide | p-200, m-400, gap-600 |
| Typography | text-body-medium, text-label-small | text-16, text-14 |
| Colors | bg-primary-surface, text-neutral-content | bg-grape-600, text-sand-800 |
Semantic Color Categories:
Color Token Structure:
/* Surface colors (for backgrounds of interactive elements) */
--color-primary-surface
--color-primary-surface-hover
--color-primary-surface-active
/* Content colors (for text) */
--color-neutral-content
--color-neutral-content-subtle
--color-neutral-content-subtler
--color-neutral-content-subtlest /* Use for disabled text */
/* Background colors (for page/container backgrounds) */
--color-neutral-background
--color-primary-background
/* Border colors */
--color-neutral-border
--color-primary-border-subtle
/* Icon colors */
--color-primary-icon
--color-negative-icon
Accent Colors (tags, charts, categories):
-bold text, -subtlest bg-bold text, -subtle bg-subtlest text, -base bg-base bgSemantic Scale:
--spacing-tightest / tightest: 2px--spacing-tighter / tighter: 4px--spacing-tight / tight: 8px--spacing-base / base: 16px--spacing-wide / wide: 24px--spacing-wider / wider: 32px--spacing-widest / widest: 40pxSemantic Scale:
text-body-smallest / --font-size-body-smallest: 10pxtext-body-smaller / --font-size-body-smaller: 12pxtext-body-small / --font-size-body-small: 14pxtext-body-medium / --font-size-body-medium: 16pxtext-label-small / --font-size-label-small: 14pxtext-label-medium / --font-size-label-medium: 16pxtext-title-small / --font-size-title-small: 18pxtext-title-medium / --font-size-title-medium: 20pxtext-title-large / --font-size-title-large: 24pxAutomatic when using semantic tokens. Never use hard-coded colors, numeric tokens (grape-600), or inline color styles.
All shared UI components are in the @humansignal/ui package:
web/libs/ui/src/lib/import { Button, Badge } from '@humansignal/ui';Browse available components in @humansignal/ui:
web/libs/ui/src/lib/yarn nx storybook storybook (port 4400)Critical: Always check @humansignal/ui before creating new components. Use Message for informational boxes, EmptyState for empty states, Button instead of <button>.
// UI components
import { Button, Badge, Message } from '@humansignal/ui';
// Icons
import { IconCheck, IconCross } from '@humansignal/icons';
// Core utilities
import { cn } from '@humansignal/core';
Some components built on shadcn/ui. Always import via @humansignal/ui, never from /src/shad/.
See tailwind.mdc for complete guidelines.
Use semantic utilities: p-tight, bg-primary-surface, text-body-medium (not p-200, bg-grape-600, text-16)
Responsive: sm:, md:, lg: utilities
Co-locate .module.css with components.
Component Tokens Pattern:
.base {
--background-color: var(--color-primary-surface);
--text-color: var(--color-primary-surface-content);
background-color: var(--background-color);
color: var(--text-color);
}
.variant-neutral {
--background-color: var(--color-neutral-surface);
--text-color: var(--color-neutral-content);
}
Tailwind in CSS: @apply flex items-center gap-tight;
Canvas Elements:
For canvas/JS rendering that cannot use CSS variables, use getTokenColor:
import { getTokenColor } from '@humansignal/ui';
ctx.fillStyle = getTokenColor('--color-primary-surface');
See react.mdc for complete React patterns.
@humansignal/ui components: kebab-case (button.tsx, empty-state.tsx)DataManager.tsx).tsx, .module.css, .stories.tsx, .test.tsxState: primary, neutral, positive, negative, warning, gradient
Size: smaller (24px), small (32px), medium (40px), large (48px+)
Look: filled (solid), outlined (border), string (text only)
Use neutral-content-subtlest for disabled text: <button disabled className="text-neutral-content-subtlest">
Use waiting prop: <Button waiting={isLoading}>Save</Button>
Always use EmptyState with icon, title, description, actions:
<EmptyState icon={<IconInbox />} title="No tasks yet" description="..." actions={<Button>Create</Button>} />
Footer Actions: All CTAs and navigation buttons in footer (default: right-aligned; "Previous" buttons: left-aligned)
Button Visual Hierarchy: See "Button Hierarchy" section.
Destructive Actions: Require confirmation. High-impact actions require typing validation ("DELETE" or entity name).
Modal Stacking: Avoid modal-over-modal. Use multi-step modals or drawers instead.
// Right-aligned footer (default)
<Modal.Footer align="right">
<Button variant="neutral" look="outlined">Cancel</Button>
<Button variant="primary" look="filled">Save Changes</Button>
</Modal.Footer>
Before creating new components, check @humansignal/ui and Storybook.
Always use existing:
<Button> not <button><Message> for info boxes<Tooltip> for tooltips<Modal> for modals<EmptyState> for empty states@humansignal/ui: kebab-case (button.tsx)DataManager.tsx)ComponentNamePropsNever hard-code values. Use semantic tokens: text-primary-content p-tight text-body-medium
Create component tokens:
.component {
--component-bg: var(--color-neutral-surface);
background: var(--component-bg);
}
Prefer rem for dimensions, px acceptable when necessary.
One primary/filled button per screen (single CTA).
Visual hierarchy by alignment:
[Cancel] [Save][Next] [Skip]Ensure layouts adapt: flex-col md:flex-row, p-tight md:p-base, text-title-medium md:text-headline-small
Use explicit Save buttons for settings/configuration (not auto-save).
Exceptions: draft content, preferences, immediate toggles.
p-200, bg-grape-600)color: #4C5FA9)<button> not <Button>/src/shad/ directlyweb/libs/ui/src/lib/web/libs/ui/src/tokens/tokens.prefix.css@humansignal/iconsyarn nx storybook storybookreact.mdc - Component structure, hooks, state managementtailwind.mdc - Utility classes, responsive designtypescript.mdc - Type conventionsfrontend-unit-tests.mdc - Testing patternsterminology.mdc - Domain terminologyimport { Button, Message, EmptyState } from '@humansignal/ui';
import { IconCheck } from '@humansignal/icons';
import { cn } from '@humansignal/core';
p-tight, m-base, gap-wide, text-body-medium, bg-primary-surface, text-neutral-content, text-neutral-content-subtlest (disabled)