The descriptive half of the design docs (ADR 0194): which components/ui primitives
exist, their slots, and each one's when-to-use — extracted from the JSDoc on the shipped
components. It is DESCRIPTIVE ONLY. The normative design law — the four pillars, the
prohibitions, and the role-token values — is founder-authored in
design-system-manifest.md and is never written here. A
when-to-use references that law; it never restates or mints it.
Source: apps/web/src/components/ui/Alert.tsx
When to use: A Manti-backed inline semantic message. Use danger for errors and another semantic variant for non-error outcomes; add kp-alert--inline when preserving a feature's existing text-only geometry.
Slots:
children— The message description.
Source: apps/web/src/components/ui/Avatar.tsx
When to use: The Manti-backed user/actor image primitive. Always pass name: it names the image and supplies the initials fallback when src is absent or fails. Reach for it for any actor identity glyph.
Slots:
fallback— Rendered internally from the first two initials ofname.
Source: apps/web/src/components/ui/Badge.tsx
When to use: A Manti-backed compact status or category chip. Keep state in text, not color alone, and use a feature class only to preserve an established Phoenix category palette.
Slots:
children— The badge label.
Source: apps/web/src/components/ui/Button.tsx
When to use: The Manti-backed base action control. Use primary for the promoted action, secondary for standard actions, tertiary for low-emphasis actions and danger for destructive actions; prefer it over a hand-rolled button.
Slots:
children— The visible label and accessible name.icon— Optional leading decorative glyph, mapped to Manti's icon slot.
Source: apps/web/src/components/ui/Card.tsx
When to use: The opinionated default for a NEW surface — a bordered, subtly-raised, padded box. Reach for Surface with explicit props only to preserve an existing shell's exact look during a migration (the composite-primitive selection rule is the manifest's, referenced not restated — see design-system-manifest.md).
Slots:
children— The card's content.
Agent directives (@agent — protected, do not regenerate):
- Prefer this composite over hand-rolling a bordered box; do not regenerate this selection guidance — it echoes the manifest's component-selection rule.
Source: apps/web/src/components/ui/CaylakBadge.tsx
When to use: Never directly — reach for SandboxMarker, which owns the ReviewBadge/CaylakBadge choice so the two cannot stack on one item. Rendered only when the server-derived sandboxedInPlace field is true, which is structurally false while PHOENIX_CAYLAK_VISIBILITY is off.
Slots:
none— Fixed copy; no children slot.
Source: apps/web/src/components/ui/atoms.tsx
When to use: The inline-code glyph — renders a <code> for an identifier, path, or short literal inside running prose. Reach for it over a styled span so the code run is semantic; for a multi-line block use a <pre>, not this inline atom.
Slots:
children— The code text.
Source: apps/web/src/components/ui/Collapsible.tsx
When to use: The Manti-backed inline disclosure. Pass the trigger and panel content to reveal optional detail while retaining keyboard and ARIA behavior.
Slots:
trigger— The disclosure control supplied through thetriggerprop.children— The region shown while the disclosure is open.
Source: apps/web/src/components/ui/CopyLinkButton.tsx
When to use: The shared paylaş (share/copy-link) control. Reach for it on any shareable item (pano post/comment, sözlük definition) — pass the canonical path and it resolves the absolute URL, copies it, and flashes inline kopyalandı/kopyalanamadı feedback (native share sheet only on coarse-pointer surfaces). Don't hand-roll per-page link logic.
Slots:
none— Renders its own label; no children slot.
Source: apps/web/src/components/ui/CountToggle.tsx
When to use: The pressable count-pill — a reaction/vote/toggle affordance that carries an aggregate count. Reach for it over a bare toggle button whenever a count rides alongside the on/off state (the reaction bar is the canonical use).
Slots:
children— The visible label; when omitted (icon-only), name the control viaaria-labelsince the icon is decorative.icon— Leading decorative glyph rendered before the label/count.
Source: apps/web/src/components/ui/Dialog.tsx
When to use: The Manti-backed modal surface for confirmations, forms and focused overlay tasks. Supply title for its accessible name and use the footer render prop when actions need the provided close callback.
Slots:
trigger— Optional element that opens the dialog.children— The dialog body.footer— Optional action row, accepting Manti's dialog render props.
Source: apps/web/src/components/ui/DraftRestoreBanner.tsx
When to use: The saved-draft restore prompt. Reach for it after a flow that may have stashed a draft across the auth round-trip — it OFFERS restore/discard rather than silently re-injecting (#1214). Wire onRestore/onDismiss to the caller's draft store.
Slots:
none— Fixed copy + two actions; no children slot.
Source: apps/web/src/components/ui/EditedIndicator.tsx
When to use: The edited-marker glyph. Reach for it on any editable entity's meta row (post, comment, definition) to signal an edit — render it unconditionally and let it self-suppress when the item is unedited or still within the grace window.
Slots:
none— Fixed copy + tooltip; no children slot.
Source: apps/web/src/components/ui/EmptyState.tsx
When to use: The inline empty-state block. Reach for it to fill a sparse region within a page (an empty feed, a zero-count list, a contribution-less profile) so the void reads as intentional. For a full-page miss use NotFoundPage, its 404 sibling, instead.
Slots:
icon— Optional decorative glyph above the title (aria-hidden).title— The required headline for the empty state.description— Optional supporting line under the title.action— Optional CTA (e.g. a Button) below the copy.
Source: apps/web/src/components/ui/Form.tsx
When to use: The native form shell around Manti's field-owning Input and Textarea components. Use it for submit semantics without introducing another field state layer.
Slots:
children— The Manti fields and form actions.
Source: apps/web/src/components/ui/Form.tsx
When to use: The Manti single-line field. Pass its label directly and use hint or error so Manti owns the field's accessible relationships.
Slots:
none— A leaf field control with its label and messages supplied as props.
Source: apps/web/src/components/ui/atoms.tsx
When to use: The keyboard-key glyph — renders a <kbd> for a shortcut key or key combo mentioned in running text (e.g. a ⌘K hint). Reach for it over a styled span so the key reads as a key semantically, not just visually.
Slots:
children— The key label (a single key or a combo).
Source: apps/web/src/components/ui/atoms.tsx
When to use: The highlight glyph — renders a <mark> to emphasize a run of text (a search-match hit, a called-out term). Reach for it over a colored span so the highlight carries the native highlight semantics.
Slots:
children— The highlighted text.
Source: apps/web/src/components/ui/Menu.tsx
When to use: The Manti-backed dropdown command list for account and contextual actions. Describe commands through items; use groups and separators for structure instead of hand-built popup content.
Slots:
trigger— The element that opens the menu.items— Commands, separators and command groups supplied throughitems.
Source: apps/web/src/components/ui/MetaRow.tsx
When to use: The muted metadata row shell — author · time · a count · an action, dot-separated. Reach for it (with MetaRow.Dot between items) for any feed row, post/definition header, or comment footer instead of hand-rolling the row.
Slots:
children— The metadata items; separate them withMetaRow.Dot.
Source: apps/web/src/components/ui/NumberInput.tsx
When to use: A Manti-backed numeric field with bounds and step controls. Prefer this over a generic Input with type="number" when numeric stepping is the interaction.
Slots:
label— Optional visible field label.
Source: apps/web/src/components/ui/Popover.tsx
When to use: The Manti-backed non-modal anchored surface for compact interactive content such as the notification preview. Use Dialog when the task must be modal.
Slots:
trigger— The element that anchors and opens the popover.children— The popover content.
Source: apps/web/src/components/ui/ReportButton.tsx
When to use: The shared bildir (report) control. Reach for it on any reportable item (pano post/comment, sözlük definition) — pass onReport to perform the mutation and it owns the in-flight lock plus the bildirildi/zaten bildirildi feedback, locking once confirmed. Don't hand-roll per-page report logic.
Slots:
none— Renders its own label; no children slot.
Source: apps/web/src/components/ui/ReviewBadge.tsx
When to use: Every "incelemede" (pending review) badge, wherever it renders — the author's own sandboxed content (post-detail, definition, profile katkıların) and the divan review queue. Never hand-roll a second one; a feature class over a raw Badge variant is how the divan chip ended up grey-on-blue (#5228).
Slots:
none— Fixed copy; no children slot.
Source: apps/web/src/components/ui/SandboxMarker.tsx
When to use: Any surface showing content that can be sandboxed — the pano feed row, post detail, comment tree node, sözlük definition entry. Renders nothing when neither wire field applies, which is also what every viewer gets with PHOENIX_CAYLAK_VISIBILITY off.
Slots:
none— Chooses a fixed-copy badge; no children slot.
Source: apps/web/src/components/ui/ScrollArea.tsx
When to use: A bounded Manti-backed scroll viewport that needs keyboard focus and draggable scrollbars while its surrounding header/footer stay fixed.
Slots:
children— Scrollable content.
Source: apps/web/src/components/ui/Select.tsx
When to use: The Manti-backed selection field for a compact fixed option list whose choices need keyboard navigation and a styled listbox.
Slots:
items— The options supplied throughitems.
Source: apps/web/src/components/ui/atoms.tsx
When to use: The loading-placeholder block — a shimmering box that reserves space for content still in flight. Reach for it to hold layout during a fetch instead of a spinner or a collapsing void; size it to the content it stands in for.
Slots:
none— Presentational; renders no children.
Source: apps/web/src/components/ui/Card.tsx
When to use: The parameterized surface shell — background/border/radius/padding/ elevation driven entirely by role-token props. Reach for it (over Card) only to reproduce an existing shell's exact look during a migration; for a new surface prefer Card's opinionated default (the selection rule is the manifest's, referenced not restated — see design-system-manifest.md).
Slots:
children— The surface's content.
Source: apps/web/src/components/ui/Switch.tsx
When to use: The Manti-backed binary setting control for an immediately applied on/off value. Supply a textual child as its label; use CountToggle when a count travels with the state.
Slots:
children— The switch's trailing accessible label.
Source: apps/web/src/components/ui/Tabs.tsx
When to use: The Manti-backed sibling-view switcher. Declare each trigger and panel through items; use line, pill or soft appearance without hand-wiring tab roles and selection state.
Slots:
items— Tab labels and their corresponding panel content.
Source: apps/web/src/components/ui/atoms.tsx
When to use: The category/kind chip — a small colored label for a post kind, topic, or status. Pass href to render it as a link chip, omit it for a static label. Reach for it over a hand-styled span for any categorical badge.
Slots:
children— The chip label.
Source: apps/web/src/components/ui/Form.tsx
When to use: The Manti multi-line field for free-form content. Pass its label directly; use kp-textarea--mono only for code or preformatted input.
Slots:
none— A leaf field control with its label and messages supplied as props.
Source: apps/web/src/components/ui/Toast.tsx
When to use: The Manti-backed transient-notification host. Mount it once near the application root and raise ephemeral status through useToast; stable ids replace.
Slots:
children— The subtree that can calluseToast.
Source: apps/web/src/components/ui/ToggleGroup.tsx
When to use: The Manti-backed compact selection set for segmented controls, filters and small fixed option lists. Supply options through items and control selection with the string-array value contract.
Slots:
items— Toggle options supplied throughitems.
Source: apps/web/src/components/ui/Tooltip.tsx
When to use: The Manti-backed hover/focus hint for short supplementary text. Never place essential information solely in a tooltip.
Slots:
children— The trigger content wrapped by Manti's inline trigger.
Source: apps/web/src/components/ui/Tooltip.tsx
When to use: Compatibility-only no-op for the former application-level provider. Manti Tooltip needs no provider; new code should not add another provider.
Slots:
children— The application subtree, returned unchanged.