# Postede UI design system Source-owned shadcn/ui with Radix primitives. Installed source is authoritative; these examples are composition recipes, not complete application state or persistence implementations. ## Rules - Read AGENTS.md, docs/lab-design-system.md and the relevant /design component page before changing UI. Installed source in src/components/ui is the API authority. - Use source-owned shadcn/Radix components from @/components/ui. Prefer named variants and semantic theme tokens; preserve Postede’s existing palette, typography, spacing and responsive behavior. - Compose Field, FieldLabel, a control, FieldDescription and FieldError for forms. Preserve names, values, validation, refs, submit types and pending/error behavior. - Give dialogs a title, avatars a fallback and icon buttons an accessible name. Keep SelectItem in SelectGroup, menu items in DropdownMenuGroup and TabsTrigger in TabsList. - Use the shared toast API from @/features/ui/toast. It preserves async actions, retries and native-modal placement through Sonner. - Use NativeDialog, NativeCheckbox, NativeSwitch and inline surface adapters only when preserving an existing host contract. Prefer declarative primitives for new independent controls; do not spread unstyled as a default. - Keep Tiptap, drag-and-drop scheduling, charts, provider previews and Posty as product compositions. Reuse their shared controls rather than replacing their interaction engines. - Add missing official components with the shadcn CLI, inspect generated files, and preserve local adaptations. Never reinitialize or overwrite customized primitives to add a component. - Update the component reference, example and agent reference together when a primitive API changes. Run npm run ui:audit, appropriate checks, and real-browser desktop/mobile verification; distinguish tested behavior from inference. ## Workflow - Inspect: Find the matching component and read its installed source. Check existing product usage before creating a new abstraction. - Compose: Start from the documented import and example. Use named variants, semantic tokens and the correct compound structure. - Preserve: Keep form, focus, state, cancellation and responsive contracts intact. Use compatibility adapters only where those contracts require them. - Verify: Exercise keyboard, Escape, disabled/pending/error states and narrow layouts. Run the UI audit and relevant tests, then update the reference. ## Foundations - Canvas: --background — Page background - Text: --foreground — Primary text - Surface: --card — Panels and cards - Elevated: --popover — Menus and overlays - Field: --field — Text controls - Muted: --muted-foreground — Supporting text - Primary: --primary — Primary actions - Selected: --accent-commit — Active and selected states - Danger: --destructive — Destructive actions and errors - Border: --border — Quiet boundaries ## Button Run an action or submit a form. Page: /design/button Source: src/components/ui/button.tsx Import: @/components/ui/button API: variant: default, outline, secondary, ghost, destructive, link; size: xs, sm, default, lg, icon variants; asChild; disabled Accessibility: Use an accessible name for icon actions. Keep a visible focus indicator. ```tsx import { Button } from "@/components/ui/button"; <> ``` ## ButtonGroup Join related actions without changing their individual behavior. Page: /design/button-group Source: src/components/ui/button-group.tsx Import: @/components/ui/button-group API: orientation: horizontal or vertical; standard div attributes Accessibility: Use distinct action labels; do not use a button group as a radio group. ```tsx import { ButtonGroup } from "@/components/ui/button-group"; import { Button } from "@/components/ui/button"; <> ``` ## Input Enter one line, search, or retain a browser-native input contract. Page: /design/input Source: src/components/ui/input.tsx Import: @/components/ui/input API: Native input props: type, name, value/defaultValue, required, disabled, ref; unstyled composition Accessibility: Keep labels associated and names stable. File, hidden, color, date/time and native radio types retain browser behavior. ```tsx import { Field, FieldLabel } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; <> Project name ``` ## Textarea Enter plain multiline content. Page: /design/textarea Source: src/components/ui/textarea.tsx Import: @/components/ui/textarea API: Native textarea props, rows, value/defaultValue, required, ref Accessibility: Do not replace the rich-text composer with Textarea. Keep an error description associated. ```tsx import { Field, FieldLabel } from "@/components/ui/field"; import { Textarea } from "@/components/ui/textarea"; <> Notes