@create-ui/cli 0.5.7 → 0.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/{chunk-RMTTHCB3.js → chunk-2ELKDGGM.js} +3 -3
  2. package/dist/{chunk-RMTTHCB3.js.map → chunk-2ELKDGGM.js.map} +1 -1
  3. package/dist/chunk-643QI2I2.js +102 -0
  4. package/dist/chunk-643QI2I2.js.map +1 -0
  5. package/dist/{chunk-NQFMXHMH.js → chunk-KQTXDVKV.js} +3 -3
  6. package/dist/chunk-KQTXDVKV.js.map +1 -0
  7. package/dist/index.js +35 -35
  8. package/dist/index.js.map +1 -1
  9. package/dist/mcp/index.js +1 -1
  10. package/dist/registry/index.js +1 -1
  11. package/dist/skills/createui/SKILL.md +201 -177
  12. package/dist/skills/createui/agents/openai.yml +1 -1
  13. package/dist/skills/createui/cli.md +42 -42
  14. package/dist/skills/createui/customization.md +20 -15
  15. package/dist/skills/createui/evals/evals.json +68 -5
  16. package/dist/skills/createui/mcp.md +14 -5
  17. package/dist/skills/createui/reference/accordion.md +127 -0
  18. package/dist/skills/createui/reference/app-store-badge.md +88 -0
  19. package/dist/skills/createui/reference/aspect-ratio.md +52 -0
  20. package/dist/skills/createui/reference/avatar.md +230 -0
  21. package/dist/skills/createui/reference/badge.md +110 -0
  22. package/dist/skills/createui/reference/breadcrumb.md +153 -0
  23. package/dist/skills/createui/reference/button-group.md +116 -0
  24. package/dist/skills/createui/reference/button.md +104 -0
  25. package/dist/skills/createui/reference/checkbox-group.md +118 -0
  26. package/dist/skills/createui/reference/checkbox.md +79 -0
  27. package/dist/skills/createui/reference/chip.md +115 -0
  28. package/dist/skills/createui/reference/close-button.md +83 -0
  29. package/dist/skills/createui/reference/command.md +69 -0
  30. package/dist/skills/createui/reference/country-flag.md +109 -0
  31. package/dist/skills/createui/reference/credit-card-input.md +76 -0
  32. package/dist/skills/createui/reference/date-input.md +71 -0
  33. package/dist/skills/createui/reference/dropdown-menu.md +164 -0
  34. package/dist/skills/createui/reference/field.md +186 -0
  35. package/dist/skills/createui/reference/info-tooltip.md +110 -0
  36. package/dist/skills/createui/reference/inline-alert.md +146 -0
  37. package/dist/skills/createui/reference/input-group.md +171 -0
  38. package/dist/skills/createui/reference/input-otp.md +130 -0
  39. package/dist/skills/createui/reference/input-stepper.md +120 -0
  40. package/dist/skills/createui/reference/input.md +118 -0
  41. package/dist/skills/createui/reference/label.md +121 -0
  42. package/dist/skills/createui/reference/pagination.md +157 -0
  43. package/dist/skills/createui/reference/password-strength.md +70 -0
  44. package/dist/skills/createui/reference/phone-input.md +77 -0
  45. package/dist/skills/createui/reference/progress.md +158 -0
  46. package/dist/skills/createui/reference/radio-group.md +133 -0
  47. package/dist/skills/createui/reference/radio.md +79 -0
  48. package/dist/skills/createui/reference/scroll-area.md +212 -0
  49. package/dist/skills/createui/reference/segmented-control.md +146 -0
  50. package/dist/skills/createui/reference/select.md +204 -0
  51. package/dist/skills/createui/reference/separator.md +99 -0
  52. package/dist/skills/createui/reference/social-login-button.md +130 -0
  53. package/dist/skills/createui/reference/spinner.md +68 -0
  54. package/dist/skills/createui/reference/status-badge.md +89 -0
  55. package/dist/skills/createui/reference/switch-group.md +122 -0
  56. package/dist/skills/createui/reference/switch.md +75 -0
  57. package/dist/skills/createui/reference/tab-menu.md +165 -0
  58. package/dist/skills/createui/reference/text-link.md +84 -0
  59. package/dist/skills/createui/reference/textarea.md +50 -0
  60. package/dist/skills/createui/reference/toast.md +162 -0
  61. package/dist/skills/createui/reference/tooltip.md +63 -0
  62. package/dist/skills/createui/rules/composition.md +41 -25
  63. package/dist/skills/createui/rules/design.md +266 -0
  64. package/dist/skills/createui/rules/forms.md +44 -15
  65. package/dist/skills/createui/rules/icons.md +64 -18
  66. package/dist/skills/createui/rules/styling.md +53 -14
  67. package/dist/utils/index.js +1 -1
  68. package/package.json +1 -1
  69. package/dist/chunk-M5DYT2NE.js +0 -64
  70. package/dist/chunk-M5DYT2NE.js.map +0 -1
  71. package/dist/chunk-NQFMXHMH.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/text-link.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/text-link.md -->
2
+
3
+ # text-link
4
+
5
+ Inline anchor link with six color variants; underline, visited and disabled states, leadingIcon/trailingIcon, asChild
6
+
7
+ Install: `npx @create-ui/cli add text-link`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { TextLink } from "@/components/ui/text-link"
13
+ ```
14
+
15
+ Also exported: `textLinkVariants`
16
+
17
+ ## TextLink props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `primary \| neutral \| inverse \| danger \| success \| info` | `primary` |
22
+ | size | `xs \| sm \| md \| lg` | `md` |
23
+ | visited | `boolean` (Prop-controlled only (purple-500 text, violet underline); the component never reacts to the CSS :visited pseudo-class) | `false` |
24
+ | disabled | `boolean` (Sets aria-disabled, tabIndex=-1 and pointer-events-none but keeps href; remove href yourself if the target is meaningless) | `false` |
25
+ | asChild | `boolean` (The child's own children become the label; TextLink clones the child and re-injects the label wrapped in its content/underline/icon spans) | `false` |
26
+ | leadingIcon | `ReactNode` | - |
27
+ | trailingIcon | `ReactNode` | - |
28
+ | underline | `boolean` (Renders a hairline span (data-slot=text-link-underline), not text-decoration; base forces no-underline, so use this prop, never the Tailwind underline class) | `false` |
29
+
30
+ Extends `React.ComponentProps<"a">`.
31
+
32
+ ## Icons
33
+
34
+ Icons go through icon props - never as children next to text, and never with sizing classes (the component sizes icons per `size`): `TextLink` (`leadingIcon` / `trailingIcon`). Import icons from `@create-ui/assets/icons` (Remix `Ri*`).
35
+
36
+ ## Examples
37
+
38
+ From `text-link-demo`:
39
+
40
+ ```tsx
41
+ import { TextLink } from "@/components/ui/text-link"
42
+
43
+ export default function TextLinkDemo() {
44
+ return <TextLink href="#">Read the documentation</TextLink>
45
+ }
46
+ ```
47
+
48
+ From `text-link-in-prose`:
49
+
50
+ ```tsx
51
+ import { TextLink } from "@/components/ui/text-link"
52
+
53
+ export default function TextLinkInProse() {
54
+ return (
55
+ <p className="text-paragraph-md text-body max-w-prose">
56
+ Create UI ships components as source files you copy into your project.
57
+ Start with the{" "}
58
+ <TextLink href="#" underline>
59
+ installation guide
60
+ </TextLink>{" "}
61
+ to scaffold a new app, then browse the{" "}
62
+ <TextLink href="#">component reference</TextLink> to see every primitive
63
+ in one place.
64
+ </p>
65
+ )
66
+ }
67
+ ```
68
+
69
+ More: `npx @create-ui/cli view text-link` or MCP `get_item_examples_from_registries` with "text-link-demo" / "text-link-example".
70
+
71
+ ## When to use
72
+ Inline link inside body copy, list items, table cells, and helper text, where the control must read as text in the line, not as a button. Renders a native `<a>` by default, or slots a router link (`next/link` etc.) via `asChild`. Do not use it when the control needs a filled hit area (use `Button`, optionally `asChild` over an `<a>`), for menu rows (`DropdownMenuItem`), or for breadcrumb trails (`BreadcrumbItem`).
73
+
74
+ ## Gotchas
75
+ - There is no `as` prop: the root is always `<a>` unless `asChild` swaps in the child element. For a non-navigation click action, slot a `<button>` via `asChild`.
76
+ - `asChild` is smarter than a plain shadcn Slot: icons and `underline` still work because TextLink extracts the child's children as the label and clones the child with its own internal spans. The child must be a single valid element:
77
+ ```tsx
78
+ <TextLink asChild underline trailingIcon={<RiArrowRightSLine />}>
79
+ <Link href="/docs">Continue</Link>
80
+ </TextLink>
81
+ ```
82
+ - The label span is `whitespace-nowrap`: a multi-word link mid-sentence never wraps and can overflow narrow prose containers; keep labels short or override on `[data-slot=text-link-content]`.
83
+ - Focus is an `outline-*` treatment (transparent at rest, colored on focus-visible) per the system-wide outline rule; do not add `ring-*` via className.
84
+ - The label span carries small per-size horizontal padding (`px-0.5` to `px-1.5`), so the link text never sits perfectly flush with adjacent prose.
@@ -0,0 +1,50 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/textarea.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/textarea.md -->
2
+
3
+ # textarea
4
+
5
+ Multi-line text input; size and state inherit from Field, resizable x/y/both with custom grip, loading spinner overlay
6
+
7
+ Install: `npx @create-ui/cli add textarea`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Textarea } from "@/components/ui/textarea"
13
+ ```
14
+
15
+ Also exported: `textareaVariants`
16
+
17
+ ## Textarea props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | size | `xs \| sm \| md` | `sm` |
22
+ | resizable | `x \| y \| both` (Use this prop, never resize-x/resize-y classes; base is resize-none and the prop hides the webkit grip and overlays the custom corner glyph.) | - |
23
+ | loading | `boolean` (Makes the textarea readOnly + aria-busy with pointer-events-none, NOT disabled; it stays in the tab order and its value still submits.) | - |
24
+
25
+ Extends `React.ComponentProps<"textarea">`.
26
+
27
+ ## Examples
28
+
29
+ From `textarea-demo`:
30
+
31
+ ```tsx
32
+ import { Textarea } from "@/components/ui/textarea"
33
+
34
+ export default function TextareaDemo() {
35
+ return <Textarea placeholder="Write something..." />
36
+ }
37
+ ```
38
+
39
+ More: `npx @create-ui/cli view textarea` or MCP `get_item_examples_from_registries` with "textarea-demo" / "textarea-example".
40
+
41
+ ## When to use
42
+ Multi-line free text: bios, messages, feedback, descriptions, comments. For single-line input use `Input`. Never place a raw `Textarea` inside an `InputGroup`; use `InputGroupTextarea` there, since the group manages size and state through its own context.
43
+
44
+ ## Gotchas
45
+ - Field cascade: `size`, `loading`, and `disabled` resolve as explicit prop ?? Field context ?? default, so explicit props win. `invalid` is OR-combined instead: `<Field invalid>` alone flips the error styling, sets `aria-invalid`, and renders the warning icon, and `aria-invalid={false}` on the textarea cannot cancel it.
46
+ - The DOM shape changes with state: a `data-slot="textarea-wrapper"` div only exists when `resizable` is set or a status icon (loading/invalid) is showing; otherwise the bare `<textarea>` is returned. `className` always lands on the textarea itself, but parent-selector CSS can break across states.
47
+ - `loading` is not `disabled`: it sets `readOnly`, `aria-busy`, and `pointer-events-none`. If you need the field skipped on submit, set `disabled` too. When `loading` and invalid are both true, the spinner wins over the warning icon.
48
+ - Resize must go through the `resizable` prop. Adding `resize-y` via `className` shows the native browser grip with no design-system glyph; the prop hides the webkit resizer and grid-stacks the custom corner icon.
49
+ - The status icon (spinner / `RiErrorWarningLine`) renders bottom-LEFT inside the textarea and is `aria-hidden`; spinner size auto-pairs with the textarea size. Communicate the actual error text via `FieldHelper`, not the icon.
50
+ - Base height is `min-h-[132px]`, so small `rows` values have no visible effect; override height with a `min-h-*` class.
@@ -0,0 +1,162 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/toast.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/toast.md -->
2
+
3
+ # toast
4
+
5
+ Notification card with icon, action and close slots plus ToastProgress countdown; seven variants by four appearances
6
+
7
+ Install: `npx @create-ui/cli add toast`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Toast, ToastBody, ToastIcon, ToastContent, ToastTitle, ToastDescription, ToastAction, ToastClose, ToastProgress } from "@/components/ui/toast"
13
+ ```
14
+
15
+ Also exported: `toastVariants`, `useToastContext`
16
+
17
+ ## Toast props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `primary \| neutral \| danger \| success \| warning \| info \| away` | `primary` |
22
+ | appearance | `solid \| soft \| outline \| default` (solid = filled, soft/outline/default = quieter surfaces) | `solid` |
23
+
24
+ Extends `React.ComponentProps<"div">`.
25
+
26
+ ## ToastProgress props
27
+
28
+ | Prop | Type | Default |
29
+ | --- | --- | --- |
30
+ | value | `number` | - |
31
+ | duration | `number` (CSS tween duration per value change (default 150ms); for a lifetime countdown set it to the toast's full lifetime in ms) | `150` |
32
+
33
+ Extends `React.ComponentProps<"div">`.
34
+
35
+ ## Examples
36
+
37
+ From `toast-demo`:
38
+
39
+ ```tsx
40
+ import { RiInformationFill } from "@create-ui/assets/icons"
41
+
42
+ import {
43
+ Toast,
44
+ ToastBody,
45
+ ToastContent,
46
+ ToastDescription,
47
+ ToastIcon,
48
+ ToastTitle,
49
+ } from "@/components/ui/toast"
50
+
51
+ export default function ToastDemo() {
52
+ return (
53
+ <Toast>
54
+ <ToastBody>
55
+ <ToastIcon>
56
+ <RiInformationFill />
57
+ </ToastIcon>
58
+ <ToastContent>
59
+ <ToastTitle>New update available</ToastTitle>
60
+ <ToastDescription>Version 2.1 is ready to install.</ToastDescription>
61
+ </ToastContent>
62
+ </ToastBody>
63
+ </Toast>
64
+ )
65
+ }
66
+ ```
67
+
68
+ From `toast-with-progress`:
69
+
70
+ ```tsx
71
+ "use client"
72
+
73
+ import * as React from "react"
74
+ import { RiInformationFill } from "@create-ui/assets/icons"
75
+
76
+ import { Button } from "@/components/ui/button"
77
+ import {
78
+ Toast,
79
+ ToastBody,
80
+ ToastContent,
81
+ ToastDescription,
82
+ ToastIcon,
83
+ ToastProgress,
84
+ ToastTitle,
85
+ } from "@/components/ui/toast"
86
+
87
+ const DURATION_MS = 5000
88
+
89
+ export default function ToastWithProgress() {
90
+ const [visible, setVisible] = React.useState(true)
91
+ const [progress, setProgress] = React.useState(0)
92
+
93
+ React.useEffect(() => {
94
+ if (!visible) return
95
+
96
+ const raf = requestAnimationFrame(() => setProgress(100))
97
+ const timeout = setTimeout(() => setVisible(false), DURATION_MS)
98
+
99
+ return () => {
100
+ cancelAnimationFrame(raf)
101
+ clearTimeout(timeout)
102
+ }
103
+ }, [visible])
104
+
105
+ if (!visible) {
106
+ return (
107
+ <Button
108
+ variant="neutral-light"
109
+ appearance="outline"
110
+ onClick={() => {
111
+ setProgress(0)
112
+ setVisible(true)
113
+ }}
114
+ >
115
+ Show toast again
116
+ </Button>
117
+ )
118
+ }
119
+
120
+ return (
121
+ <Toast variant="info" appearance="soft">
122
+ <ToastBody>
123
+ <ToastIcon>
124
+ <RiInformationFill />
125
+ </ToastIcon>
126
+ <ToastContent>
127
+ <ToastTitle>Auto-dismissing in 5s</ToastTitle>
128
+ <ToastDescription>
129
+ The progress bar tracks the remaining lifetime of this toast.
130
+ </ToastDescription>
131
+ </ToastContent>
132
+ </ToastBody>
133
+ <ToastProgress value={progress} duration={DURATION_MS} />
134
+ </Toast>
135
+ )
136
+ }
137
+ ```
138
+
139
+ More: `npx @create-ui/cli view toast` or MCP `get_item_examples_from_registries` with "toast-demo" / "toast-example".
140
+
141
+ ## When to use
142
+
143
+ Ephemeral, floating confirmation of an action ("Draft saved", "Copied"); render it in a screen-level fixed container. Not for status that belongs to a section (use `InlineAlert`), blocking confirm/cancel decisions (use `Dialog`), or per-field validation (use `Field` helper/error text).
144
+
145
+ ## Gotchas
146
+
147
+ - There is no `toast()` function, no `Toaster`, no app-level provider, no portal, no queue or positioning system. `Toast` is just the card; render active toasts from your own state into a fixed container. Do NOT install or import `sonner`.
148
+ - Dismiss lifecycle: `ToastClose` starts a 300ms fade/scale exit; the root's `onDismiss` fires only after the transition ends, then the component renders `null`. Remove the toast from your list in `onDismiss`, not in `ToastClose`'s `onClick`. Once dismissed it stays hidden; re-showing requires a remount (state toggle or new `key`).
149
+ - `ToastProgress` never ticks by itself and is `aria-hidden` (purely visual). For an auto-dismissing toast, set `duration` to the lifetime, flip `value` from 0 to 100 inside `requestAnimationFrame`, and pair it with a `setTimeout` that actually hides the toast:
150
+
151
+ ```tsx
152
+ React.useEffect(() => {
153
+ const raf = requestAnimationFrame(() => setProgress(100))
154
+ const timeout = setTimeout(() => setVisible(false), DURATION_MS)
155
+ return () => { cancelAnimationFrame(raf); clearTimeout(timeout) }
156
+ }, [])
157
+ // <ToastProgress value={progress} duration={DURATION_MS} />
158
+ ```
159
+
160
+ - `ToastIcon`, `ToastDescription`, `ToastAction`, `ToastClose`, and `ToastProgress` read the Toast context, so they only style correctly inside `<Toast>`. Don't hand-set Button variants on `ToastAction`/`ToastClose` (the appearance-matched pairing is automatic) or color/size classes on the icon (the svg is auto-sized `size-5` and colored per variant/appearance).
161
+ - The root is hard-coded `w-[410px] min-w-[300px]`; override the width via `className` for narrow viewports.
162
+ - The root renders `role="status"` (polite live region); pass `role="alert"` for urgent messages. No Escape-key handling is wired; dismissal happens only through `ToastClose` (or `useToastContext().dismiss`).
@@ -0,0 +1,63 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/tooltip.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/tooltip.md -->
2
+
3
+ # tooltip
4
+
5
+ Radix hover tooltip for any trigger element; five color variants, optional arrow, side and offset control
6
+
7
+ Install: `npx @create-ui/cli add tooltip`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
13
+ ```
14
+
15
+ Also exported: `tooltipContentVariants`
16
+
17
+ ## TooltipContent props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | children | `ReactNode` | - |
22
+ | className | `string` | - |
23
+ | variant | `primary \| neutral \| inverse \| danger \| info` | `primary` |
24
+ | showArrow | `boolean` (effective offset = sideOffset when true; sideOffset + 5 when false, so the chip keeps a visible gap without the caret) | `false` |
25
+ | side | `top \| bottom \| left \| right` (defaults to bottom; shadcn/Radix default to top, do not assume top) | `bottom` |
26
+ | sideOffset | `number` | `2.5` |
27
+
28
+ Extends `React.ComponentProps<typeof TooltipPrimitive.Content>`.
29
+
30
+ ## Examples
31
+
32
+ From `tooltip-demo`:
33
+
34
+ ```tsx
35
+ "use client"
36
+
37
+ import { Button } from "@/components/ui/button"
38
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
39
+
40
+ export default function TooltipDemo() {
41
+ return (
42
+ <Tooltip defaultOpen>
43
+ <TooltipTrigger asChild>
44
+ <Button appearance="outline" size="sm">
45
+ Hover me
46
+ </Button>
47
+ </TooltipTrigger>
48
+ <TooltipContent showArrow>Add to library</TooltipContent>
49
+ </Tooltip>
50
+ )
51
+ }
52
+ ```
53
+
54
+ More: `npx @create-ui/cli view tooltip` or MCP `get_item_examples_from_registries` with "tooltip-demo" / "tooltip-example".
55
+
56
+ ## When to use
57
+ Tooltip is a short hover/focus hint for icon-only buttons, truncated labels, and similar read-only context. Content must stay brief: the chip caps at max-w-[200px] and wraps. For content with links, buttons, or inputs there is no popover component - put it inline; for a help icon next to a label use InfoTooltip; for post-action messages use Toast; for a persistent in-flow note use InlineAlert.
58
+ ## Gotchas
59
+ - Tooltip self-provides its Radix Provider and passes delayDuration (default 0) explicitly to both Provider and Root, so an ancestor TooltipProvider's delayDuration never reaches it. Set delay per instance: `<Tooltip delayDuration={400}>`. The exported TooltipProvider only matters for raw TooltipPrimitive.Root subtrees.
60
+ - align is hardcoded to "center" and Omit-ed from the passthrough type; it cannot be overridden.
61
+ - TooltipTrigger should use asChild wrapping a focusable registry element (Button, link); the trigger always gets an `inline-flex` class so the wrapped child lays out consistently.
62
+ - TooltipArrow is internal and not exported; the only way to render the caret is `showArrow` on TooltipContent, and its fill auto-matches the chosen variant. Never try to style or compose the arrow separately.
63
+ - InfoTooltip is a separate ready-made component for inline "what is this" affordances; do not hand-compose Tooltip around an info icon.
@@ -1,6 +1,6 @@
1
1
  # Component Composition
2
2
 
3
- How Create UI components fit together. Compose primitives never reroll a `<select>`, a custom callout, or a hand-styled loading button when a component already exists. Every component name below is in the `@createui` registry; add any of them with `npx @create-ui/cli add <name>`.
3
+ How Create UI components fit together. Compose primitives - never reroll a `<select>`, a custom callout, or a hand-styled loading button when a component already exists. Every component name below is in the `@createui` registry; add any of them with `npx @create-ui/cli add <name>`.
4
4
 
5
5
  ## Contents
6
6
 
@@ -8,16 +8,16 @@ How Create UI components fit together. Compose primitives — never reroll a `<s
8
8
  - Callouts use InlineAlert
9
9
  - Toasts use the Toast component
10
10
  - Choosing between overlay components
11
- - Button has a `loading` prop never hand-build a spinner button
11
+ - Button has a `loading` prop - never hand-build a spinner button
12
12
  - Tabbed navigation uses TabMenu
13
- - Avatar always needs AvatarFallback
13
+ - Avatar composition (AvatarText, not AvatarFallback)
14
14
  - Use existing components instead of custom markup
15
15
 
16
16
  ---
17
17
 
18
18
  ## Items always inside their Group component
19
19
 
20
- Never render menu/list items directly inside the content container always wrap them in the matching `*Group`.
20
+ Never render menu/list items directly inside the content container - always wrap them in the matching `*Group`.
21
21
 
22
22
  **Incorrect:**
23
23
 
@@ -42,17 +42,17 @@ Never render menu/list items directly inside the content container — always wr
42
42
 
43
43
  This applies to every group-based component:
44
44
 
45
- | Item | Group |
46
- |------|-------|
47
- | `SelectItem`, `SelectLabel` | `SelectGroup` |
48
- | `DropdownMenuItem`, `DropdownMenuLabel` | `DropdownMenuGroup` |
49
- | `CommandItem` | `CommandGroup` |
45
+ | Item | Group | Requirement |
46
+ |------|-------|-------------|
47
+ | `SelectItem`, `SelectLabel` | `SelectGroup` | Structural - always wrap |
48
+ | `CommandItem` | `CommandGroup` | Structural - always wrap |
49
+ | `DropdownMenuItem`, `DropdownMenuLabel` | `DropdownMenuGroup` | Semantic - group related items (with `DropdownMenuLabel` / `DropdownMenuSeparator`); a lone item may sit directly in `DropdownMenuContent` |
50
50
 
51
51
  ---
52
52
 
53
53
  ## Callouts use InlineAlert
54
54
 
55
- Use `InlineAlert` for callouts. Don't hand-roll a styled `<div>` and don't look for a shadcn-style generic alert (or a page-banner) component; `InlineAlert` is the callout primitive.
55
+ Use `InlineAlert` for callouts. Don't hand-roll a styled `<div>` - and don't look for a shadcn-style generic alert (or a page-banner) component; `InlineAlert` is the callout primitive.
56
56
 
57
57
  **Incorrect:**
58
58
 
@@ -94,13 +94,13 @@ import {
94
94
  </InlineAlert>
95
95
  ```
96
96
 
97
- `InlineAlert` takes `variant` (`primary` | `neutral` | `danger` | `success` | `warning` | `info` | `away`) and `appearance` (`default` | `solid` | `soft` | `outline`). For a dismissible callout, add `<InlineAlertClose />` as a direct child and handle `onDismiss` on the root. For a full-width page banner, place an `InlineAlert` in a full-width container there is no separate banner component.
97
+ `InlineAlert` takes `variant` (`primary` | `neutral` | `danger` | `success` | `warning` | `info` | `away`) and `appearance` (`default` | `solid` | `soft` | `outline`). For a dismissible callout, add `<InlineAlertClose />` as a direct child and handle `onDismiss` on the root. For a full-width page banner, place an `InlineAlert` in a full-width container - there is no separate banner component.
98
98
 
99
99
  ---
100
100
 
101
101
  ## Toasts use the Toast component
102
102
 
103
- Toasts are the registry's own `toast` component **not `sonner`**. There is no `toast()` function to import; compose the `Toast` parts and render it from your notification state.
103
+ Toasts are the registry's own `toast` component - **not `sonner`**. There is no `toast()` function to import; compose the `Toast` parts and render it from your notification state.
104
104
 
105
105
  **Incorrect:**
106
106
 
@@ -140,7 +140,7 @@ import {
140
140
 
141
141
  `Toast` takes `variant` (`primary` | `neutral` | `danger` | `success` | `warning` | `info` | `away`) and `appearance` (`solid` | `soft` | `outline` | `default`), plus an `onDismiss` callback. Add `<ToastClose />` for an explicit close affordance and `<ToastProgress />` for an auto-dismiss countdown bar.
142
142
 
143
- There is no provider, queue, or stacking system you own the notification state and the placement. Render active toasts from your state into a fixed container:
143
+ There is no provider, queue, or stacking system - you own the notification state and the placement. Render active toasts from your state into a fixed container:
144
144
 
145
145
  ```tsx
146
146
  const [toasts, setToasts] = React.useState<AppToast[]>([])
@@ -168,7 +168,7 @@ const [toasts, setToasts] = React.useState<AppToast[]>([])
168
168
 
169
169
  ## Choosing between overlay components
170
170
 
171
- Pick the overlay that matches the interaction these are the overlays that exist.
171
+ Pick the overlay that matches the interaction - these are the overlays that exist.
172
172
 
173
173
  | Use case | Component |
174
174
  |----------|-----------|
@@ -177,13 +177,13 @@ Pick the overlay that matches the interaction — these are the overlays that ex
177
177
  | Action menu on a trigger | `DropdownMenu` |
178
178
  | Command palette / quick switcher | `Command` (inline) / `CommandDialog` (modal) |
179
179
 
180
- There is **no dialog, popover, sheet, drawer, alert-dialog, or hover-card component**. The only modal surface is `CommandDialog` (shipped with `command`). For other modal or contextual-panel needs, don't invent a lookalike from raw markup surface the flow inline (e.g. an expanding section, a dedicated route, or an `InlineAlert` confirmation) or ask the user before hand-rolling an overlay.
180
+ There is **no dialog, popover, sheet, drawer, alert-dialog, or hover-card component**. The only modal surface is `CommandDialog` (shipped with `command`). For other modal or contextual-panel needs, don't invent a lookalike from raw markup - surface the flow inline (e.g. an expanding section, a dedicated route, or an `InlineAlert` confirmation) or ask the user before hand-rolling an overlay.
181
181
 
182
182
  ---
183
183
 
184
- ## Button has a `loading` prop never hand-build a spinner button
184
+ ## Button has a `loading` prop - never hand-build a spinner button
185
185
 
186
- `Button` ships a real `loading` prop. It renders the `Spinner` and disables interaction for you do not compose a `Spinner` + `disabled` button by hand.
186
+ `Button` ships a real `loading` prop. It renders the `Spinner` and disables interaction for you - do not compose a `Spinner` + `disabled` button by hand.
187
187
 
188
188
  **Incorrect:**
189
189
 
@@ -200,7 +200,7 @@ There is **no dialog, popover, sheet, drawer, alert-dialog, or hover-card compon
200
200
  <Button loading>Saving…</Button>
201
201
  ```
202
202
 
203
- For icons, use the `leadingIcon` / `trailingIcon` props (or `iconOnly` for an icon-only button) never wrap raw `<svg>` children or add sizing classes; the component sizes the icon per `size`.
203
+ For icons, use the `leadingIcon` / `trailingIcon` props (or `iconOnly` for an icon-only button) - never wrap raw `<svg>` children or add sizing classes; the component sizes the icon per `size`.
204
204
 
205
205
  ```tsx
206
206
  import { RiSearchLine } from "@create-ui/assets/icons"
@@ -209,13 +209,13 @@ import { RiSearchLine } from "@create-ui/assets/icons"
209
209
  <Button iconOnly aria-label="Search" leadingIcon={<RiSearchLine />} />
210
210
  ```
211
211
 
212
- Remember the Button API: `variant` is `primary | neutral-solid | neutral-light | danger | success | inverse-solid | inverse-light`, and the outlined/ghost looks come from `appearance` (`solid | outline | ghost | soft`). There is no outline or destructive `variant` value use `appearance="outline"` for the outlined look and `variant="danger"` for destructive actions. See `rules/styling.md` for the full variant/appearance reference.
212
+ Remember the Button API: `variant` is `primary | neutral-solid | neutral-light | danger | success | inverse-solid | inverse-light`, and the outlined/ghost looks come from `appearance` (`solid | outline | ghost | soft`). There is no outline or destructive `variant` value - use `appearance="outline"` for the outlined look and `variant="danger"` for destructive actions. See `rules/styling.md` for the full variant/appearance reference.
213
213
 
214
214
  ---
215
215
 
216
216
  ## Tabbed navigation uses TabMenu
217
217
 
218
- Tabs are the `tab-menu` component there is no shadcn-style tabs / tabs-list / tabs-trigger set. `TabMenu` wraps `TabMenuItem`s and owns the selection (`defaultValue`, or controlled `value` / `onValueChange`). It renders the menu only render the active panel yourself from the value; there is no content component.
218
+ Tabs are the `tab-menu` component - there is no shadcn-style tabs / tabs-list / tabs-trigger set. `TabMenu` wraps `TabMenuItem`s and owns the selection (`defaultValue`, or controlled `value` / `onValueChange`). It renders the menu only - render the active panel yourself from the value; there is no content component.
219
219
 
220
220
  ```tsx
221
221
  import { TabMenu, TabMenuItem } from "@/components/ui/tab-menu"
@@ -234,27 +234,43 @@ const [tab, setTab] = React.useState("overview")
234
234
 
235
235
  ---
236
236
 
237
- ## Avatar always needs AvatarFallback
237
+ ## Avatar composition (AvatarText, not AvatarFallback)
238
238
 
239
- Always include `AvatarFallback` so something renders when the image is missing or fails to load.
239
+ **`AvatarFallback` does not exist in Create UI** - the fallback/initials slot is `AvatarText`. It renders only while the sibling `AvatarImage` has not loaded (or when there is no image), so an image avatar should always carry one:
240
240
 
241
241
  ```tsx
242
+ import { Avatar, AvatarImage, AvatarText } from "@/components/ui/avatar"
243
+
244
+ <Avatar>
245
+ <AvatarImage src="/avatar.png" alt="User" />
246
+ <AvatarText>JD</AvatarText>
247
+ </Avatar>
248
+ ```
249
+
250
+ Initials-only avatars pick a real color `variant`; presence comes from `AvatarBadge` + `AvatarBadgeStatus`; stacks are `AvatarGroup` (+ `AvatarGroupAction` for the "+5" affordance):
251
+
252
+ ```tsx
253
+ <Avatar variant="weak-blue"><AvatarText>YT</AvatarText></Avatar>
254
+
242
255
  <Avatar>
243
256
  <AvatarImage src="/avatar.png" alt="User" />
244
- <AvatarFallback>JD</AvatarFallback>
257
+ <AvatarText>JD</AvatarText>
258
+ <AvatarBadge><AvatarBadgeStatus variant="online" /></AvatarBadge>
245
259
  </Avatar>
246
260
  ```
247
261
 
262
+ See `reference/avatar.md` for the full prop tables (`size` `2xs`–`2xl`, `shape`, 55 color variants, `AvatarIcon`, `AvatarRing`).
263
+
248
264
  ---
249
265
 
250
266
  ## Use existing components instead of custom markup
251
267
 
252
- If a primitive already covers the job, use it don't reach for raw elements or utility-class fakes.
268
+ If a primitive already covers the job, use it - don't reach for raw elements or utility-class fakes.
253
269
 
254
270
  | Instead of | Use |
255
271
  |---|---|
256
272
  | `<hr>` or `<div className="border-t">` | `<Separator />` |
257
273
  | `<span className="rounded-full bg-green-100 …">` | `<Badge variant="success">Active</Badge>` |
258
- | A status dot built from a styled `<span>` | `<StatusBadge variant="success" />` (it renders the dot only put the label next to it). `variant`: `primary`, `danger`, `success`, `warning`, `info`, `highlighted`, `away`, `verified`, `cyan`, `lime`, `neutral`, `white` note `danger`, not `error` |
274
+ | A status dot built from a styled `<span>` | `<StatusBadge variant="success" />` (it renders the dot only - put the label next to it). `variant`: `primary`, `danger`, `success`, `warning`, `info`, `highlighted`, `away`, `verified`, `cyan`, `lime`, `neutral`, `white` - note `danger`, not `error` |
259
275
  | A removable tag built from `<span>` + `<button>` | `<Chip onClose={…}>…</Chip>` |
260
276
  | A hand-rolled `animate-spin` loading indicator | `<Spinner />` |