@neynar/ui 1.0.1 → 1.0.3

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 (68) hide show
  1. package/context7.json +17 -0
  2. package/llm/components/accordion.llm.md +205 -0
  3. package/llm/components/alert-dialog.llm.md +289 -0
  4. package/llm/components/alert.llm.md +310 -0
  5. package/llm/components/aspect-ratio.llm.md +110 -0
  6. package/llm/components/avatar.llm.md +282 -0
  7. package/llm/components/badge.llm.md +185 -0
  8. package/llm/components/blockquote.llm.md +86 -0
  9. package/llm/components/breadcrumb.llm.md +245 -0
  10. package/llm/components/button-group.llm.md +248 -0
  11. package/llm/components/button.llm.md +247 -0
  12. package/llm/components/calendar.llm.md +252 -0
  13. package/llm/components/card.llm.md +356 -0
  14. package/llm/components/carousel.llm.md +281 -0
  15. package/llm/components/chart.llm.md +278 -0
  16. package/llm/components/checkbox.llm.md +234 -0
  17. package/llm/components/code.llm.md +75 -0
  18. package/llm/components/collapsible.llm.md +271 -0
  19. package/llm/components/color-mode.llm.md +196 -0
  20. package/llm/components/combobox.llm.md +346 -0
  21. package/llm/components/command.llm.md +353 -0
  22. package/llm/components/context-menu.llm.md +368 -0
  23. package/llm/components/dialog.llm.md +283 -0
  24. package/llm/components/drawer.llm.md +326 -0
  25. package/llm/components/dropdown-menu.llm.md +404 -0
  26. package/llm/components/empty.llm.md +282 -0
  27. package/llm/components/field.llm.md +303 -0
  28. package/llm/components/first-light.llm.md +129 -0
  29. package/llm/components/hover-card.llm.md +278 -0
  30. package/llm/components/input-group.llm.md +334 -0
  31. package/llm/components/input-otp.llm.md +270 -0
  32. package/llm/components/input.llm.md +197 -0
  33. package/llm/components/item.llm.md +347 -0
  34. package/llm/components/kbd.llm.md +221 -0
  35. package/llm/components/label.llm.md +219 -0
  36. package/llm/components/menubar.llm.md +378 -0
  37. package/llm/components/navigation-menu.llm.md +320 -0
  38. package/llm/components/pagination.llm.md +337 -0
  39. package/llm/components/popover.llm.md +278 -0
  40. package/llm/components/progress.llm.md +259 -0
  41. package/llm/components/radio-group.llm.md +269 -0
  42. package/llm/components/resizable.llm.md +222 -0
  43. package/llm/components/scroll-area.llm.md +290 -0
  44. package/llm/components/select.llm.md +338 -0
  45. package/llm/components/separator.llm.md +129 -0
  46. package/llm/components/sheet.llm.md +275 -0
  47. package/llm/components/sidebar.llm.md +528 -0
  48. package/llm/components/skeleton.llm.md +140 -0
  49. package/llm/components/slider.llm.md +213 -0
  50. package/llm/components/sonner.llm.md +299 -0
  51. package/llm/components/spinner.llm.md +187 -0
  52. package/llm/components/switch.llm.md +258 -0
  53. package/llm/components/table.llm.md +334 -0
  54. package/llm/components/tabs.llm.md +245 -0
  55. package/llm/components/text.llm.md +108 -0
  56. package/llm/components/textarea.llm.md +236 -0
  57. package/llm/components/title.llm.md +88 -0
  58. package/llm/components/toggle-group.llm.md +228 -0
  59. package/llm/components/toggle.llm.md +235 -0
  60. package/llm/components/tooltip.llm.md +191 -0
  61. package/llm/contributing.llm.md +273 -0
  62. package/llm/hooks.llm.md +91 -0
  63. package/llm/index.llm.md +178 -0
  64. package/llm/theming.llm.md +381 -0
  65. package/llm/utilities.llm.md +97 -0
  66. package/llms-full.txt +15995 -0
  67. package/llms.txt +182 -0
  68. package/package.json +5 -1
@@ -0,0 +1,303 @@
1
+ # Field
2
+
3
+ Comprehensive form field system with labels, descriptions, error handling, and flexible layouts for building accessible forms.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import {
9
+ Field,
10
+ FieldLabel,
11
+ FieldContent,
12
+ FieldDescription,
13
+ FieldError,
14
+ FieldGroup,
15
+ FieldSet,
16
+ FieldLegend,
17
+ FieldSeparator,
18
+ FieldTitle,
19
+ } from "@neynar/ui/field"
20
+ ```
21
+
22
+ ## Anatomy
23
+
24
+ ```tsx
25
+ <Field orientation="vertical" data-invalid={hasError}>
26
+ <FieldLabel htmlFor="input-id">Label Text</FieldLabel>
27
+ <FieldContent>
28
+ <Input id="input-id" />
29
+ <FieldDescription>Helper text</FieldDescription>
30
+ <FieldError errors={errors} />
31
+ </FieldContent>
32
+ </Field>
33
+ ```
34
+
35
+ ## Components
36
+
37
+ | Component | Description |
38
+ |-----------|-------------|
39
+ | Field | Base field wrapper with orientation support |
40
+ | FieldLabel | Label for the field input |
41
+ | FieldContent | Container for input + description + error |
42
+ | FieldDescription | Helper text providing context |
43
+ | FieldError | Error message display with auto-deduplication |
44
+ | FieldGroup | Container for multiple related fields |
45
+ | FieldSet | Semantic fieldset container for field groups |
46
+ | FieldLegend | Legend for FieldSet with variant styles |
47
+ | FieldSeparator | Visual separator between field sections |
48
+ | FieldTitle | Title text for checkbox/switch fields |
49
+
50
+ ## Props
51
+
52
+ ### Field
53
+
54
+ | Prop | Type | Default | Description |
55
+ |------|------|---------|-------------|
56
+ | orientation | "vertical" \| "horizontal" \| "responsive" | "vertical" | Layout orientation |
57
+ | data-invalid | boolean | - | Apply error styling when true |
58
+ | data-disabled | boolean | - | Apply disabled styling when true |
59
+
60
+ ### FieldLabel
61
+
62
+ Extends Label component. Use `htmlFor` to associate with input.
63
+
64
+ ### FieldContent
65
+
66
+ Container with consistent spacing for input + description + error.
67
+
68
+ ### FieldDescription
69
+
70
+ Helper text automatically styled for placement. Supports links with underline styling.
71
+
72
+ ### FieldError
73
+
74
+ | Prop | Type | Default | Description |
75
+ |------|------|---------|-------------|
76
+ | errors | Array<{ message?: string }> | - | Error objects to display |
77
+ | children | ReactNode | - | Custom error content |
78
+
79
+ Automatically deduplicates errors by message. Shows single error as text, multiple errors as bulleted list.
80
+
81
+ ### FieldGroup
82
+
83
+ Container for multiple fields with consistent spacing. Provides `@container/field-group` for responsive layouts.
84
+
85
+ ### FieldSet
86
+
87
+ Semantic `<fieldset>` element for grouping related fields. Use with FieldLegend.
88
+
89
+ ### FieldLegend
90
+
91
+ | Prop | Type | Default | Description |
92
+ |------|------|---------|-------------|
93
+ | variant | "legend" \| "label" | "legend" | Visual style variant |
94
+
95
+ ### FieldSeparator
96
+
97
+ | Prop | Type | Default | Description |
98
+ |------|------|---------|-------------|
99
+ | children | ReactNode | - | Optional label text on separator |
100
+
101
+ ### FieldTitle
102
+
103
+ Title text for fields with embedded controls (checkboxes, switches). Use inside FieldLabel.
104
+
105
+ ## Orientation Variants
106
+
107
+ | Variant | Behavior |
108
+ |---------|----------|
109
+ | vertical | Label and input stacked vertically (default) |
110
+ | horizontal | Label and input side by side |
111
+ | responsive | Vertical on mobile, horizontal on larger screens (requires FieldGroup) |
112
+
113
+ ## Data Attributes
114
+
115
+ | Attribute | When Present | Used For |
116
+ |-----------|--------------|----------|
117
+ | data-invalid | Field has errors | Error styling |
118
+ | data-disabled | Field is disabled | Disabled styling |
119
+ | data-orientation | Always | Current orientation value |
120
+ | data-slot | Always | Component identification |
121
+
122
+ ## Examples
123
+
124
+ ### Basic Field
125
+
126
+ ```tsx
127
+ <Field>
128
+ <FieldLabel htmlFor="username">Username</FieldLabel>
129
+ <Input id="username" placeholder="Enter username" />
130
+ </Field>
131
+ ```
132
+
133
+ ### Field with Description
134
+
135
+ ```tsx
136
+ <Field>
137
+ <FieldLabel htmlFor="email">Email Address</FieldLabel>
138
+ <FieldContent>
139
+ <Input id="email" type="email" placeholder="your@email.com" />
140
+ <FieldDescription>We'll never share your email</FieldDescription>
141
+ </FieldContent>
142
+ </Field>
143
+ ```
144
+
145
+ ### Field with Error State
146
+
147
+ ```tsx
148
+ const [errors, setErrors] = useState({ email: { message: "Invalid email" } })
149
+
150
+ <Field data-invalid={!!errors.email}>
151
+ <FieldLabel htmlFor="email">Email *</FieldLabel>
152
+ <FieldContent>
153
+ <Input
154
+ id="email"
155
+ type="email"
156
+ aria-invalid={!!errors.email}
157
+ />
158
+ <FieldError errors={[errors.email]} />
159
+ </FieldContent>
160
+ </Field>
161
+ ```
162
+
163
+ ### Horizontal Layout with Switch
164
+
165
+ ```tsx
166
+ <Field orientation="horizontal">
167
+ <FieldLabel htmlFor="notifications">
168
+ <Switch id="notifications" />
169
+ <div>
170
+ <FieldTitle>Enable Notifications</FieldTitle>
171
+ <FieldDescription>Receive email updates</FieldDescription>
172
+ </div>
173
+ </FieldLabel>
174
+ </Field>
175
+ ```
176
+
177
+ ### Grouped Fields with Separator
178
+
179
+ ```tsx
180
+ <FieldGroup>
181
+ <Field>
182
+ <FieldLabel htmlFor="name">Name</FieldLabel>
183
+ <Input id="name" />
184
+ </Field>
185
+
186
+ <FieldSeparator>Security Settings</FieldSeparator>
187
+
188
+ <Field>
189
+ <FieldLabel htmlFor="password">Password</FieldLabel>
190
+ <Input id="password" type="password" />
191
+ </Field>
192
+ </FieldGroup>
193
+ ```
194
+
195
+ ### Field Set with Radio Group
196
+
197
+ ```tsx
198
+ <FieldSet>
199
+ <FieldLegend variant="label">Event Type</FieldLegend>
200
+ <FieldGroup>
201
+ <RadioGroup value={value} onValueChange={setValue}>
202
+ <Field orientation="horizontal">
203
+ <FieldLabel htmlFor="option-1">
204
+ <RadioGroupItem value="option1" id="option-1" />
205
+ <div>
206
+ <FieldTitle>Option One</FieldTitle>
207
+ <FieldDescription>First choice description</FieldDescription>
208
+ </div>
209
+ </FieldLabel>
210
+ </Field>
211
+
212
+ <Field orientation="horizontal">
213
+ <FieldLabel htmlFor="option-2">
214
+ <RadioGroupItem value="option2" id="option-2" />
215
+ <div>
216
+ <FieldTitle>Option Two</FieldTitle>
217
+ <FieldDescription>Second choice description</FieldDescription>
218
+ </div>
219
+ </FieldLabel>
220
+ </Field>
221
+ </RadioGroup>
222
+ </FieldGroup>
223
+ </FieldSet>
224
+ ```
225
+
226
+ ### Multiple Errors
227
+
228
+ ```tsx
229
+ <Field data-invalid={true}>
230
+ <FieldLabel htmlFor="password">Password</FieldLabel>
231
+ <FieldContent>
232
+ <Input id="password" type="password" aria-invalid={true} />
233
+ <FieldError
234
+ errors={[
235
+ { message: "Must be at least 8 characters" },
236
+ { message: "Must contain a number" },
237
+ { message: "Must contain a special character" },
238
+ ]}
239
+ />
240
+ </FieldContent>
241
+ </Field>
242
+ ```
243
+
244
+ ### Responsive Layout
245
+
246
+ ```tsx
247
+ <FieldGroup>
248
+ <Field orientation="responsive">
249
+ <FieldLabel htmlFor="phone">Phone Number</FieldLabel>
250
+ <FieldContent>
251
+ <Input id="phone" placeholder="+1 (555) 123-4567" />
252
+ <FieldDescription>
253
+ Vertical on mobile, horizontal on larger screens
254
+ </FieldDescription>
255
+ </FieldContent>
256
+ </Field>
257
+ </FieldGroup>
258
+ ```
259
+
260
+ ### Disabled Field
261
+
262
+ ```tsx
263
+ <Field data-disabled={true}>
264
+ <FieldLabel htmlFor="readonly">Read Only Field</FieldLabel>
265
+ <FieldContent>
266
+ <Input
267
+ id="readonly"
268
+ disabled
269
+ defaultValue="Cannot edit"
270
+ />
271
+ <FieldDescription>This field cannot be modified</FieldDescription>
272
+ </FieldContent>
273
+ </Field>
274
+ ```
275
+
276
+ ## Accessibility
277
+
278
+ - Uses semantic HTML elements (`fieldset`, `legend`, `label`)
279
+ - FieldError uses `role="alert"` for screen reader announcements
280
+ - Supports `aria-invalid` on inputs for error states
281
+ - FieldLabel properly associates with inputs via `htmlFor`
282
+ - FieldDescription provides additional context without cluttering labels
283
+ - Disabled state reduces opacity for visual indication
284
+
285
+ ## Best Practices
286
+
287
+ - Always use `htmlFor` on FieldLabel to associate with input `id`
288
+ - Set `data-invalid` on Field and `aria-invalid` on input for error states
289
+ - Use FieldContent when you have description or error messages
290
+ - For checkbox/switch fields, use horizontal orientation with FieldTitle
291
+ - Use FieldSet/FieldLegend for semantically related field groups
292
+ - Use FieldGroup for visual grouping without semantic fieldset
293
+ - Set `data-disabled` on Field when input is disabled
294
+ - Use FieldSeparator to organize long forms into sections
295
+
296
+ ## Related
297
+
298
+ - [Input](./input.llm.md) - Text input component
299
+ - [Textarea](./textarea.llm.md) - Multi-line text input
300
+ - [Checkbox](./checkbox.llm.md) - Checkbox input
301
+ - [Switch](./switch.llm.md) - Toggle switch
302
+ - [Radio Group](./radio-group.llm.md) - Radio button group
303
+ - [Label](./label.llm.md) - Base label component
@@ -0,0 +1,129 @@
1
+ # First Light
2
+
3
+ SVG filter component that enables hand-drawn wobble effects for the First Light theme.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { FirstLightFilters } from "@neynar/ui/first-light"
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Render once in your root layout when using the First Light theme:
14
+
15
+ ```tsx
16
+ // app/layout.tsx
17
+ import "@neynar/ui/themes/first-light";
18
+ import { FirstLightFilters } from "@neynar/ui/first-light";
19
+ import { ColorModeInitializer } from "@neynar/ui/color-mode";
20
+
21
+ export default function Layout({ children }) {
22
+ return (
23
+ <html lang="en" suppressHydrationWarning>
24
+ <head>
25
+ <ColorModeInitializer />
26
+ </head>
27
+ <body>
28
+ <FirstLightFilters />
29
+ {children}
30
+ </body>
31
+ </html>
32
+ );
33
+ }
34
+ ```
35
+
36
+ ## Props
37
+
38
+ No props. Zero configuration.
39
+
40
+ ## How It Works
41
+
42
+ Renders an invisible SVG containing `<filter>` definitions that create displacement effects using fractal noise. The First Light theme CSS references these filters via `filter: url(#first-light-filter)`.
43
+
44
+ Without this component, the theme works but edges are straight instead of wobbly.
45
+
46
+ ## Filter Definitions
47
+
48
+ | Filter ID | Effect | Use Case |
49
+ |-----------|--------|----------|
50
+ | `#first-light-filter` | Standard wobble | Default, applied to most components |
51
+ | `#first-light-filter-light` | Subtle wobble | Barely noticeable, for delicate elements |
52
+ | `#first-light-filter-heavy` | Pronounced wobble | More dramatic hand-drawn effect |
53
+
54
+ ### Filter Parameters
55
+
56
+ | Filter | Base Frequency | Octaves | Scale |
57
+ |--------|----------------|---------|-------|
58
+ | Standard | 0.015 | 2 | 1.5 |
59
+ | Light | 0.006 | 1 | 0.4 |
60
+ | Heavy | 0.012 | 3 | 1.5 |
61
+
62
+ ## CSS Classes
63
+
64
+ The First Light theme provides utility classes to apply filters:
65
+
66
+ ```tsx
67
+ // Apply heavier wobble
68
+ <Card className="first-light-heavy">...</Card>
69
+
70
+ // Apply lighter wobble
71
+ <Button className="first-light-light">Subtle</Button>
72
+ ```
73
+
74
+ | Class | Effect |
75
+ |-------|--------|
76
+ | `.first-light-light` | Applies `#first-light-filter-light` |
77
+ | `.first-light-heavy` | Applies `#first-light-filter-heavy` |
78
+
79
+ ## Technical Details
80
+
81
+ ```tsx
82
+ // The component renders this (simplified):
83
+ <svg aria-hidden="true" style={{ position: "absolute", width: 0, height: 0 }}>
84
+ <defs>
85
+ <filter id="first-light-filter">
86
+ <feTurbulence type="fractalNoise" baseFrequency="0.015" numOctaves="2" />
87
+ <feDisplacementMap scale="1.5" xChannelSelector="R" yChannelSelector="G" />
88
+ </filter>
89
+ {/* + light and heavy variants */}
90
+ </defs>
91
+ </svg>
92
+ ```
93
+
94
+ - Uses `feTurbulence` for organic noise generation
95
+ - Uses `feDisplacementMap` to distort element edges
96
+ - Each filter uses different seed for variety
97
+ - Filter extends beyond element bounds (x="-3%" etc.) to avoid clipping
98
+
99
+ ## Theme Integration
100
+
101
+ The First Light theme automatically applies filters to components via CSS:
102
+
103
+ ```css
104
+ /* In first-light.css */
105
+ .theme-first-light [data-slot="card"],
106
+ .theme-first-light [data-slot="button"],
107
+ /* ... etc ... */ {
108
+ filter: url(#first-light-filter);
109
+ }
110
+ ```
111
+
112
+ ## Performance
113
+
114
+ - SVG is hidden and takes no layout space
115
+ - Filters are GPU-accelerated in modern browsers
116
+ - Minimal memory footprint (single SVG with 3 filters)
117
+ - No runtime JavaScript after initial render
118
+
119
+ ## Accessibility
120
+
121
+ - SVG has `aria-hidden="true"`
122
+ - Purely decorative - no impact on screen readers
123
+ - Does not affect content readability
124
+ - Motion-safe (no animation)
125
+
126
+ ## Related
127
+
128
+ - [Theming](../theming.llm.md) - Full theming documentation
129
+ - First Light theme: `@neynar/ui/themes/first-light`
@@ -0,0 +1,278 @@
1
+ # HoverCard
2
+
3
+ Displays rich preview content when hovering over a trigger element.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { HoverCard, HoverCardTrigger, HoverCardContent } from "@neynar/ui/hover-card"
9
+ ```
10
+
11
+ ## Anatomy
12
+
13
+ ```tsx
14
+ <HoverCard>
15
+ <HoverCardTrigger>
16
+ <a href="#">Hover over me</a>
17
+ </HoverCardTrigger>
18
+ <HoverCardContent>
19
+ Preview content appears here
20
+ </HoverCardContent>
21
+ </HoverCard>
22
+ ```
23
+
24
+ ## Components
25
+
26
+ | Component | Description |
27
+ |-----------|-------------|
28
+ | HoverCard | Root container, manages hover state and timing |
29
+ | HoverCardTrigger | Element that triggers the hover card (link, button, text, avatar) |
30
+ | HoverCardContent | Content container with automatic portal, positioning, and animations |
31
+
32
+ ## Props
33
+
34
+ ### HoverCard
35
+
36
+ Inherits all props from `@base-ui/react/preview-card` Root component.
37
+
38
+ | Prop | Type | Default | Description |
39
+ |------|------|---------|-------------|
40
+ | open | boolean | - | Controlled open state |
41
+ | defaultOpen | boolean | false | Uncontrolled initial open state |
42
+ | onOpenChange | (open: boolean) => void | - | Called when open state changes |
43
+
44
+ ### HoverCardTrigger
45
+
46
+ Inherits all props from `@base-ui/react/preview-card` Trigger component.
47
+
48
+ | Prop | Type | Default | Description |
49
+ |------|------|---------|-------------|
50
+ | render | ReactElement \| function | - | Custom element or render function for the trigger |
51
+
52
+ The `render` prop accepts a ReactElement or function for customization:
53
+
54
+ ```tsx
55
+ // As a ReactElement
56
+ <HoverCardTrigger render={<Button variant="outline">Hover</Button>}>
57
+ Content
58
+ </HoverCardTrigger>
59
+
60
+ // As a function
61
+ <HoverCardTrigger render={(props) => <a {...props} href="#">Link</a>}>
62
+ Content
63
+ </HoverCardTrigger>
64
+ ```
65
+
66
+ ### HoverCardContent
67
+
68
+ Automatically renders portal and positioner. Combines props from Popup and Positioner components.
69
+
70
+ | Prop | Type | Default | Description |
71
+ |------|------|---------|-------------|
72
+ | side | "top" \| "right" \| "bottom" \| "left" | "bottom" | Which side of trigger to position the card |
73
+ | sideOffset | number | 4 | Distance from trigger in pixels |
74
+ | align | "start" \| "center" \| "end" | "center" | How to align relative to the trigger |
75
+ | alignOffset | number | 4 | Additional alignment axis offset in pixels |
76
+ | className | string | - | Custom CSS classes (merged with defaults) |
77
+ | initialFocus | boolean \| RefObject \| function | - | Element to focus when opened |
78
+ | finalFocus | boolean \| RefObject \| function | - | Element to focus when closed |
79
+
80
+ ## Data Attributes
81
+
82
+ Use these for custom styling and animations:
83
+
84
+ | Attribute | When Present | Description |
85
+ |-----------|--------------|-------------|
86
+ | data-open | Card is open | Apply open state styles |
87
+ | data-closed | Card is closed | Apply closed state styles |
88
+ | data-side | Always | Value: "top" \| "right" \| "bottom" \| "left" |
89
+ | data-align | Always | Value: "start" \| "center" \| "end" |
90
+ | data-starting-style | Opening animation | Initial animation state |
91
+ | data-ending-style | Closing animation | Final animation state |
92
+
93
+ ## Examples
94
+
95
+ ### User Profile Preview
96
+
97
+ ```tsx
98
+ <HoverCard>
99
+ <HoverCardTrigger>
100
+ <button className="inline-flex items-center gap-2">
101
+ <Avatar size="sm">
102
+ <AvatarImage src="/user.jpg" />
103
+ <AvatarFallback>DR</AvatarFallback>
104
+ </Avatar>
105
+ <span className="font-medium">@dwr</span>
106
+ </button>
107
+ </HoverCardTrigger>
108
+ <HoverCardContent className="w-80">
109
+ <div className="space-y-3">
110
+ <div className="flex items-start justify-between">
111
+ <div className="flex items-center gap-3">
112
+ <Avatar size="lg">
113
+ <AvatarImage src="/user.jpg" />
114
+ <AvatarFallback>DR</AvatarFallback>
115
+ </Avatar>
116
+ <div>
117
+ <p className="font-semibold">Dan Romero</p>
118
+ <p className="text-muted-foreground text-sm">@dwr</p>
119
+ </div>
120
+ </div>
121
+ <Button size="sm">Follow</Button>
122
+ </div>
123
+ <p className="text-sm">
124
+ Building Farcaster and Warpcast. Previously VP Eng at Coinbase.
125
+ </p>
126
+ <div className="flex items-center gap-4 text-sm">
127
+ <div>
128
+ <span className="font-semibold">124.5K</span>{" "}
129
+ <span className="text-muted-foreground">followers</span>
130
+ </div>
131
+ <div>
132
+ <span className="font-semibold">428</span>{" "}
133
+ <span className="text-muted-foreground">following</span>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ </HoverCardContent>
138
+ </HoverCard>
139
+ ```
140
+
141
+ ### Simple Text Preview
142
+
143
+ ```tsx
144
+ <p>
145
+ Learn more about{" "}
146
+ <HoverCard>
147
+ <HoverCardTrigger>
148
+ <a href="#" className="text-primary hover:underline">
149
+ typography
150
+ </a>
151
+ </HoverCardTrigger>
152
+ <HoverCardContent>
153
+ <p className="text-sm">
154
+ Typography is the art and science of arranging type to make written
155
+ language clear, visually appealing, and effective.
156
+ </p>
157
+ </HoverCardContent>
158
+ </HoverCard>
159
+ {" "}in design.
160
+ </p>
161
+ ```
162
+
163
+ ### Positioned Above with Custom Width
164
+
165
+ ```tsx
166
+ <HoverCard>
167
+ <HoverCardTrigger>
168
+ <Badge variant="secondary" className="cursor-pointer">
169
+ React 19
170
+ </Badge>
171
+ </HoverCardTrigger>
172
+ <HoverCardContent side="top" className="w-96">
173
+ <div className="space-y-2">
174
+ <h4 className="text-sm font-semibold">React 19</h4>
175
+ <p className="text-muted-foreground text-xs leading-relaxed">
176
+ Latest version of React with improved concurrent rendering,
177
+ automatic batching, and new hooks for better performance.
178
+ </p>
179
+ </div>
180
+ </HoverCardContent>
181
+ </HoverCard>
182
+ ```
183
+
184
+ ### Rich Content with Avatar and Actions
185
+
186
+ ```tsx
187
+ <HoverCard>
188
+ <HoverCardTrigger>
189
+ <Button variant="outline">Farcaster Protocol</Button>
190
+ </HoverCardTrigger>
191
+ <HoverCardContent className="w-72">
192
+ <div className="space-y-3">
193
+ <div className="flex items-start gap-3">
194
+ <Avatar size="sm">
195
+ <AvatarFallback>FC</AvatarFallback>
196
+ </Avatar>
197
+ <div className="flex-1 space-y-1">
198
+ <h4 className="text-sm font-semibold">Farcaster Protocol</h4>
199
+ <p className="text-muted-foreground text-xs">
200
+ A sufficiently decentralized social network.
201
+ </p>
202
+ </div>
203
+ </div>
204
+ <div className="flex gap-2">
205
+ <Button size="xs" variant="secondary">Learn More</Button>
206
+ <Button size="xs" variant="outline">Documentation</Button>
207
+ </div>
208
+ </div>
209
+ </HoverCardContent>
210
+ </HoverCard>
211
+ ```
212
+
213
+ ### Multiple Triggers in Feed
214
+
215
+ ```tsx
216
+ <div className="space-y-4">
217
+ {posts.map((post) => (
218
+ <div key={post.id} className="border rounded-lg p-4">
219
+ <div className="mb-2 flex items-center gap-2">
220
+ <HoverCard>
221
+ <HoverCardTrigger>
222
+ <button className="inline-flex items-center gap-2">
223
+ <Avatar size="sm">
224
+ <AvatarImage src={post.author.avatar} />
225
+ <AvatarFallback>{post.author.initials}</AvatarFallback>
226
+ </Avatar>
227
+ <span className="font-medium hover:underline">
228
+ @{post.author.username}
229
+ </span>
230
+ </button>
231
+ </HoverCardTrigger>
232
+ <HoverCardContent className="w-80">
233
+ <UserProfilePreview user={post.author} />
234
+ </HoverCardContent>
235
+ </HoverCard>
236
+ <span className="text-muted-foreground text-sm">{post.time}</span>
237
+ </div>
238
+ <p className="text-sm">{post.content}</p>
239
+ </div>
240
+ ))}
241
+ </div>
242
+ ```
243
+
244
+ ## Keyboard
245
+
246
+ HoverCard is primarily mouse/touch interaction, but keyboard navigation is supported:
247
+
248
+ | Key | Action |
249
+ |-----|--------|
250
+ | Hover | Open hover card after delay |
251
+ | Mouse leave | Close hover card after delay |
252
+ | Tab | Navigate through interactive elements inside content |
253
+ | Escape | Close hover card immediately |
254
+
255
+ ## Accessibility
256
+
257
+ - Automatically manages focus when opening/closing
258
+ - Content is rendered in a portal to avoid z-index issues
259
+ - Uses ARIA attributes for screen reader support
260
+ - Supports keyboard navigation for interactive content
261
+ - Trigger remains accessible and keyboard-navigable
262
+ - Respects user's motion preferences for animations
263
+
264
+ ## Styling Notes
265
+
266
+ - Default width is `w-64` (256px), customize with `className`
267
+ - Uses frosted glass effect with `bg-popover` at 75% opacity and backdrop blur
268
+ - Includes entry/exit animations via data attributes
269
+ - Side-specific slide animations (slides from opposite direction)
270
+ - Respects `--transform-origin` CSS variable for proper animation origins
271
+ - Compatible with all themes (classic, frosted, sketch)
272
+
273
+ ## Related
274
+
275
+ - [Tooltip](/components/tooltip.llm.md) - For simple text hints (non-interactive)
276
+ - [Popover](/components/popover.llm.md) - For click-triggered interactive content
277
+ - [Dialog](/components/dialog.llm.md) - For modal overlays
278
+ - [Avatar](/components/avatar.llm.md) - Commonly used in hover card triggers