@neynar/ui 1.0.1 → 1.0.2
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.
- package/context7.json +17 -0
- package/llm/components/accordion.llm.md +205 -0
- package/llm/components/alert-dialog.llm.md +289 -0
- package/llm/components/alert.llm.md +310 -0
- package/llm/components/aspect-ratio.llm.md +110 -0
- package/llm/components/avatar.llm.md +282 -0
- package/llm/components/badge.llm.md +185 -0
- package/llm/components/blockquote.llm.md +86 -0
- package/llm/components/breadcrumb.llm.md +245 -0
- package/llm/components/button-group.llm.md +248 -0
- package/llm/components/button.llm.md +247 -0
- package/llm/components/calendar.llm.md +252 -0
- package/llm/components/card.llm.md +356 -0
- package/llm/components/carousel.llm.md +281 -0
- package/llm/components/chart.llm.md +278 -0
- package/llm/components/checkbox.llm.md +234 -0
- package/llm/components/code.llm.md +75 -0
- package/llm/components/collapsible.llm.md +271 -0
- package/llm/components/color-mode.llm.md +196 -0
- package/llm/components/combobox.llm.md +346 -0
- package/llm/components/command.llm.md +353 -0
- package/llm/components/context-menu.llm.md +368 -0
- package/llm/components/dialog.llm.md +283 -0
- package/llm/components/drawer.llm.md +326 -0
- package/llm/components/dropdown-menu.llm.md +404 -0
- package/llm/components/empty.llm.md +282 -0
- package/llm/components/field.llm.md +303 -0
- package/llm/components/first-light.llm.md +129 -0
- package/llm/components/hover-card.llm.md +278 -0
- package/llm/components/input-group.llm.md +334 -0
- package/llm/components/input-otp.llm.md +270 -0
- package/llm/components/input.llm.md +197 -0
- package/llm/components/item.llm.md +347 -0
- package/llm/components/kbd.llm.md +221 -0
- package/llm/components/label.llm.md +219 -0
- package/llm/components/menubar.llm.md +378 -0
- package/llm/components/navigation-menu.llm.md +320 -0
- package/llm/components/pagination.llm.md +337 -0
- package/llm/components/popover.llm.md +278 -0
- package/llm/components/progress.llm.md +259 -0
- package/llm/components/radio-group.llm.md +269 -0
- package/llm/components/resizable.llm.md +222 -0
- package/llm/components/scroll-area.llm.md +290 -0
- package/llm/components/select.llm.md +338 -0
- package/llm/components/separator.llm.md +129 -0
- package/llm/components/sheet.llm.md +275 -0
- package/llm/components/sidebar.llm.md +528 -0
- package/llm/components/skeleton.llm.md +140 -0
- package/llm/components/slider.llm.md +213 -0
- package/llm/components/sonner.llm.md +299 -0
- package/llm/components/spinner.llm.md +187 -0
- package/llm/components/switch.llm.md +258 -0
- package/llm/components/table.llm.md +334 -0
- package/llm/components/tabs.llm.md +245 -0
- package/llm/components/text.llm.md +108 -0
- package/llm/components/textarea.llm.md +236 -0
- package/llm/components/title.llm.md +88 -0
- package/llm/components/toggle-group.llm.md +228 -0
- package/llm/components/toggle.llm.md +235 -0
- package/llm/components/tooltip.llm.md +191 -0
- package/llm/contributing.llm.md +273 -0
- package/llm/hooks.llm.md +91 -0
- package/llm/index.llm.md +178 -0
- package/llm/theming.llm.md +381 -0
- package/llm/utilities.llm.md +97 -0
- package/llms-full.txt +15995 -0
- package/llms.txt +182 -0
- package/package.json +5 -1
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# Pagination
|
|
2
|
+
|
|
3
|
+
A composable pagination component for navigating multi-page data sets with semantic HTML and full keyboard accessibility.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
Pagination,
|
|
10
|
+
PaginationContent,
|
|
11
|
+
PaginationItem,
|
|
12
|
+
PaginationLink,
|
|
13
|
+
PaginationPrevious,
|
|
14
|
+
PaginationNext,
|
|
15
|
+
PaginationEllipsis,
|
|
16
|
+
} from "@neynar/ui/pagination"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Anatomy
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
<Pagination>
|
|
23
|
+
<PaginationContent>
|
|
24
|
+
<PaginationItem>
|
|
25
|
+
<PaginationPrevious href="#" />
|
|
26
|
+
</PaginationItem>
|
|
27
|
+
<PaginationItem>
|
|
28
|
+
<PaginationLink href="#">1</PaginationLink>
|
|
29
|
+
</PaginationItem>
|
|
30
|
+
<PaginationItem>
|
|
31
|
+
<PaginationLink href="#" isActive>2</PaginationLink>
|
|
32
|
+
</PaginationItem>
|
|
33
|
+
<PaginationItem>
|
|
34
|
+
<PaginationLink href="#">3</PaginationLink>
|
|
35
|
+
</PaginationItem>
|
|
36
|
+
<PaginationItem>
|
|
37
|
+
<PaginationEllipsis />
|
|
38
|
+
</PaginationItem>
|
|
39
|
+
<PaginationItem>
|
|
40
|
+
<PaginationLink href="#">10</PaginationLink>
|
|
41
|
+
</PaginationItem>
|
|
42
|
+
<PaginationItem>
|
|
43
|
+
<PaginationNext href="#" />
|
|
44
|
+
</PaginationItem>
|
|
45
|
+
</PaginationContent>
|
|
46
|
+
</Pagination>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Components
|
|
50
|
+
|
|
51
|
+
| Component | Description |
|
|
52
|
+
|-----------|-------------|
|
|
53
|
+
| `Pagination` | Root navigation container with semantic `<nav>` element |
|
|
54
|
+
| `PaginationContent` | Flex list container for pagination items |
|
|
55
|
+
| `PaginationItem` | Wrapper for individual pagination elements |
|
|
56
|
+
| `PaginationLink` | Clickable page number link |
|
|
57
|
+
| `PaginationPrevious` | Previous page control with chevron + "Previous" label |
|
|
58
|
+
| `PaginationNext` | Next page control with chevron + "Next" label |
|
|
59
|
+
| `PaginationEllipsis` | Ellipsis indicator for skipped pages |
|
|
60
|
+
|
|
61
|
+
## Props
|
|
62
|
+
|
|
63
|
+
### Pagination
|
|
64
|
+
|
|
65
|
+
Extends `React.ComponentProps<"nav">`.
|
|
66
|
+
|
|
67
|
+
Root container with `role="navigation"` and `aria-label="pagination"`.
|
|
68
|
+
|
|
69
|
+
### PaginationContent
|
|
70
|
+
|
|
71
|
+
Extends `React.ComponentProps<"ul">`.
|
|
72
|
+
|
|
73
|
+
Renders as a flexbox list with gap spacing between items.
|
|
74
|
+
|
|
75
|
+
### PaginationItem
|
|
76
|
+
|
|
77
|
+
Extends `React.ComponentProps<"li">`.
|
|
78
|
+
|
|
79
|
+
Simple list item wrapper for pagination elements.
|
|
80
|
+
|
|
81
|
+
### PaginationLink
|
|
82
|
+
|
|
83
|
+
| Prop | Type | Default | Description |
|
|
84
|
+
|------|------|---------|-------------|
|
|
85
|
+
| `isActive` | `boolean` | `false` | Highlights the current active page |
|
|
86
|
+
| `size` | `"default" \| "sm" \| "lg" \| "icon"` | `"icon"` | Button size variant |
|
|
87
|
+
| `href` | `string` | - | Link destination |
|
|
88
|
+
|
|
89
|
+
Plus all standard `<a>` element props.
|
|
90
|
+
|
|
91
|
+
**Notes:**
|
|
92
|
+
- Uses Button component with `render` prop for link semantics
|
|
93
|
+
- Active pages use `outline` variant, inactive use `ghost`
|
|
94
|
+
- Sets `aria-current="page"` when `isActive={true}`
|
|
95
|
+
- Renders with `data-active` attribute for custom styling
|
|
96
|
+
|
|
97
|
+
### PaginationPrevious
|
|
98
|
+
|
|
99
|
+
Extends `PaginationLink` props.
|
|
100
|
+
|
|
101
|
+
**Auto-behaviors:**
|
|
102
|
+
- Sets `aria-label="Go to previous page"`
|
|
103
|
+
- Uses `size="default"` by default
|
|
104
|
+
- Displays chevron icon + "Previous" text (text hidden on mobile via `hidden sm:block`)
|
|
105
|
+
|
|
106
|
+
### PaginationNext
|
|
107
|
+
|
|
108
|
+
Extends `PaginationLink` props.
|
|
109
|
+
|
|
110
|
+
**Auto-behaviors:**
|
|
111
|
+
- Sets `aria-label="Go to next page"`
|
|
112
|
+
- Uses `size="default"` by default
|
|
113
|
+
- Displays "Next" text (hidden on mobile) + chevron icon
|
|
114
|
+
|
|
115
|
+
### PaginationEllipsis
|
|
116
|
+
|
|
117
|
+
Extends `React.ComponentProps<"span">`.
|
|
118
|
+
|
|
119
|
+
**Auto-behaviors:**
|
|
120
|
+
- Sets `aria-hidden` to hide from screen readers
|
|
121
|
+
- Includes screen reader text "More pages"
|
|
122
|
+
- Displays horizontal ellipsis icon
|
|
123
|
+
|
|
124
|
+
## Data Attributes
|
|
125
|
+
|
|
126
|
+
All components include `data-slot` attributes for targeted styling:
|
|
127
|
+
|
|
128
|
+
| Attribute | Component |
|
|
129
|
+
|-----------|-----------|
|
|
130
|
+
| `data-slot="pagination"` | Pagination |
|
|
131
|
+
| `data-slot="pagination-content"` | PaginationContent |
|
|
132
|
+
| `data-slot="pagination-item"` | PaginationItem |
|
|
133
|
+
| `data-slot="pagination-link"` | PaginationLink |
|
|
134
|
+
| `data-slot="pagination-ellipsis"` | PaginationEllipsis |
|
|
135
|
+
|
|
136
|
+
PaginationLink also includes:
|
|
137
|
+
- `data-active="true"` when `isActive={true}`
|
|
138
|
+
|
|
139
|
+
## Examples
|
|
140
|
+
|
|
141
|
+
### Basic Pagination
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
<Pagination>
|
|
145
|
+
<PaginationContent>
|
|
146
|
+
<PaginationItem>
|
|
147
|
+
<PaginationPrevious href="#" />
|
|
148
|
+
</PaginationItem>
|
|
149
|
+
<PaginationItem>
|
|
150
|
+
<PaginationLink href="#">1</PaginationLink>
|
|
151
|
+
</PaginationItem>
|
|
152
|
+
<PaginationItem>
|
|
153
|
+
<PaginationLink href="#" isActive>2</PaginationLink>
|
|
154
|
+
</PaginationItem>
|
|
155
|
+
<PaginationItem>
|
|
156
|
+
<PaginationLink href="#">3</PaginationLink>
|
|
157
|
+
</PaginationItem>
|
|
158
|
+
<PaginationItem>
|
|
159
|
+
<PaginationNext href="#" />
|
|
160
|
+
</PaginationItem>
|
|
161
|
+
</PaginationContent>
|
|
162
|
+
</Pagination>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### With Ellipsis (Large Data Sets)
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<Pagination>
|
|
169
|
+
<PaginationContent>
|
|
170
|
+
<PaginationItem>
|
|
171
|
+
<PaginationPrevious href="#" />
|
|
172
|
+
</PaginationItem>
|
|
173
|
+
<PaginationItem>
|
|
174
|
+
<PaginationLink href="#">1</PaginationLink>
|
|
175
|
+
</PaginationItem>
|
|
176
|
+
<PaginationItem>
|
|
177
|
+
<PaginationLink href="#" isActive>2</PaginationLink>
|
|
178
|
+
</PaginationItem>
|
|
179
|
+
<PaginationItem>
|
|
180
|
+
<PaginationLink href="#">3</PaginationLink>
|
|
181
|
+
</PaginationItem>
|
|
182
|
+
<PaginationItem>
|
|
183
|
+
<PaginationEllipsis />
|
|
184
|
+
</PaginationItem>
|
|
185
|
+
<PaginationItem>
|
|
186
|
+
<PaginationLink href="#">42</PaginationLink>
|
|
187
|
+
</PaginationItem>
|
|
188
|
+
<PaginationItem>
|
|
189
|
+
<PaginationNext href="#" />
|
|
190
|
+
</PaginationItem>
|
|
191
|
+
</PaginationContent>
|
|
192
|
+
</Pagination>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Controlled with React State
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
function APILogsTable() {
|
|
199
|
+
const [currentPage, setCurrentPage] = useState(1)
|
|
200
|
+
const totalPages = 42
|
|
201
|
+
|
|
202
|
+
function handlePageClick(page: number) {
|
|
203
|
+
setCurrentPage(page)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<div>
|
|
208
|
+
{/* Your table content */}
|
|
209
|
+
|
|
210
|
+
<Pagination>
|
|
211
|
+
<PaginationContent>
|
|
212
|
+
<PaginationItem>
|
|
213
|
+
<PaginationPrevious
|
|
214
|
+
href="#"
|
|
215
|
+
onClick={(e) => {
|
|
216
|
+
e.preventDefault()
|
|
217
|
+
if (currentPage > 1) handlePageClick(currentPage - 1)
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
220
|
+
</PaginationItem>
|
|
221
|
+
<PaginationItem>
|
|
222
|
+
<PaginationLink
|
|
223
|
+
href="#"
|
|
224
|
+
isActive={currentPage === 1}
|
|
225
|
+
onClick={(e) => {
|
|
226
|
+
e.preventDefault()
|
|
227
|
+
handlePageClick(1)
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
230
|
+
1
|
|
231
|
+
</PaginationLink>
|
|
232
|
+
</PaginationItem>
|
|
233
|
+
<PaginationItem>
|
|
234
|
+
<PaginationLink
|
|
235
|
+
href="#"
|
|
236
|
+
isActive={currentPage === 2}
|
|
237
|
+
onClick={(e) => {
|
|
238
|
+
e.preventDefault()
|
|
239
|
+
handlePageClick(2)
|
|
240
|
+
}}
|
|
241
|
+
>
|
|
242
|
+
2
|
|
243
|
+
</PaginationLink>
|
|
244
|
+
</PaginationItem>
|
|
245
|
+
<PaginationItem>
|
|
246
|
+
<PaginationEllipsis />
|
|
247
|
+
</PaginationItem>
|
|
248
|
+
<PaginationItem>
|
|
249
|
+
<PaginationLink
|
|
250
|
+
href="#"
|
|
251
|
+
onClick={(e) => {
|
|
252
|
+
e.preventDefault()
|
|
253
|
+
handlePageClick(totalPages)
|
|
254
|
+
}}
|
|
255
|
+
>
|
|
256
|
+
{totalPages}
|
|
257
|
+
</PaginationLink>
|
|
258
|
+
</PaginationItem>
|
|
259
|
+
<PaginationItem>
|
|
260
|
+
<PaginationNext
|
|
261
|
+
href="#"
|
|
262
|
+
onClick={(e) => {
|
|
263
|
+
e.preventDefault()
|
|
264
|
+
if (currentPage < totalPages) handlePageClick(currentPage + 1)
|
|
265
|
+
}}
|
|
266
|
+
/>
|
|
267
|
+
</PaginationItem>
|
|
268
|
+
</PaginationContent>
|
|
269
|
+
</Pagination>
|
|
270
|
+
</div>
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Middle Page State (Dual Ellipsis)
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
<Pagination>
|
|
279
|
+
<PaginationContent>
|
|
280
|
+
<PaginationItem>
|
|
281
|
+
<PaginationPrevious href="#" />
|
|
282
|
+
</PaginationItem>
|
|
283
|
+
<PaginationItem>
|
|
284
|
+
<PaginationLink href="#">1</PaginationLink>
|
|
285
|
+
</PaginationItem>
|
|
286
|
+
<PaginationItem>
|
|
287
|
+
<PaginationEllipsis />
|
|
288
|
+
</PaginationItem>
|
|
289
|
+
<PaginationItem>
|
|
290
|
+
<PaginationLink href="#">12</PaginationLink>
|
|
291
|
+
</PaginationItem>
|
|
292
|
+
<PaginationItem>
|
|
293
|
+
<PaginationLink href="#" isActive>13</PaginationLink>
|
|
294
|
+
</PaginationItem>
|
|
295
|
+
<PaginationItem>
|
|
296
|
+
<PaginationLink href="#">14</PaginationLink>
|
|
297
|
+
</PaginationItem>
|
|
298
|
+
<PaginationItem>
|
|
299
|
+
<PaginationEllipsis />
|
|
300
|
+
</PaginationItem>
|
|
301
|
+
<PaginationItem>
|
|
302
|
+
<PaginationLink href="#">25</PaginationLink>
|
|
303
|
+
</PaginationItem>
|
|
304
|
+
<PaginationItem>
|
|
305
|
+
<PaginationNext href="#" />
|
|
306
|
+
</PaginationItem>
|
|
307
|
+
</PaginationContent>
|
|
308
|
+
</Pagination>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Minimal (Controls Only)
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
<Pagination>
|
|
315
|
+
<PaginationContent>
|
|
316
|
+
<PaginationItem>
|
|
317
|
+
<PaginationPrevious href="#" />
|
|
318
|
+
</PaginationItem>
|
|
319
|
+
<PaginationItem>
|
|
320
|
+
<PaginationNext href="#" />
|
|
321
|
+
</PaginationItem>
|
|
322
|
+
</PaginationContent>
|
|
323
|
+
</Pagination>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Accessibility
|
|
327
|
+
|
|
328
|
+
- Uses semantic `<nav>` element with `role="navigation"` and `aria-label="pagination"`
|
|
329
|
+
- Active page links include `aria-current="page"` for screen reader context
|
|
330
|
+
- Previous/Next controls have descriptive `aria-label` attributes
|
|
331
|
+
- Ellipsis is hidden from screen readers via `aria-hidden` but includes visually hidden text "More pages"
|
|
332
|
+
- All links are keyboard navigable via Tab key
|
|
333
|
+
- Mobile-responsive: "Previous"/"Next" labels hidden on small screens
|
|
334
|
+
|
|
335
|
+
## Related
|
|
336
|
+
|
|
337
|
+
- [Button](./button.llm.md) - Used internally for pagination links
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
Floating content panel anchored to a trigger element for contextual information, forms, or interactive content.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
Popover,
|
|
10
|
+
PopoverTrigger,
|
|
11
|
+
PopoverContent,
|
|
12
|
+
PopoverHeader,
|
|
13
|
+
PopoverTitle,
|
|
14
|
+
PopoverDescription,
|
|
15
|
+
} from "@neynar/ui/popover"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Anatomy
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
<Popover>
|
|
22
|
+
<PopoverTrigger>
|
|
23
|
+
<Button>Open</Button>
|
|
24
|
+
</PopoverTrigger>
|
|
25
|
+
<PopoverContent>
|
|
26
|
+
<PopoverHeader>
|
|
27
|
+
<PopoverTitle>Title</PopoverTitle>
|
|
28
|
+
<PopoverDescription>Description</PopoverDescription>
|
|
29
|
+
</PopoverHeader>
|
|
30
|
+
{/* Content */}
|
|
31
|
+
</PopoverContent>
|
|
32
|
+
</Popover>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Components
|
|
36
|
+
|
|
37
|
+
| Component | Description |
|
|
38
|
+
|-----------|-------------|
|
|
39
|
+
| Popover | Root container managing open state |
|
|
40
|
+
| PopoverTrigger | Button that opens the popover |
|
|
41
|
+
| PopoverContent | Main content panel with portal and positioning |
|
|
42
|
+
| PopoverHeader | Optional wrapper for title and description |
|
|
43
|
+
| PopoverTitle | Heading label (h2 element) |
|
|
44
|
+
| PopoverDescription | Optional description text |
|
|
45
|
+
|
|
46
|
+
## Props
|
|
47
|
+
|
|
48
|
+
### Popover
|
|
49
|
+
|
|
50
|
+
Root component managing state. Use `open`/`onOpenChange` for controlled state.
|
|
51
|
+
|
|
52
|
+
| Prop | Type | Default | Description |
|
|
53
|
+
|------|------|---------|-------------|
|
|
54
|
+
| open | boolean | - | Controlled open state |
|
|
55
|
+
| defaultOpen | boolean | false | Initial open state (uncontrolled) |
|
|
56
|
+
| onOpenChange | (open: boolean) => void | - | Callback when open state changes |
|
|
57
|
+
| modal | boolean \| "trap-focus" | false | Modal behavior: `true` locks scroll and traps focus, `"trap-focus"` only traps focus |
|
|
58
|
+
|
|
59
|
+
### PopoverTrigger
|
|
60
|
+
|
|
61
|
+
Opens the popover when clicked. Renders a button by default.
|
|
62
|
+
|
|
63
|
+
| Prop | Type | Default | Description |
|
|
64
|
+
|------|------|---------|-------------|
|
|
65
|
+
| render | ReactElement | - | Custom element to use as trigger |
|
|
66
|
+
| openOnHover | boolean | false | Open popover on hover instead of click |
|
|
67
|
+
| delay | number | 300 | Hover delay in ms (requires openOnHover) |
|
|
68
|
+
|
|
69
|
+
### PopoverContent
|
|
70
|
+
|
|
71
|
+
Automatically renders portal and positioner. Includes fade and zoom animations.
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Default | Description |
|
|
74
|
+
|------|------|---------|-------------|
|
|
75
|
+
| side | "top" \| "right" \| "bottom" \| "left" | "bottom" | Which side of trigger to display on |
|
|
76
|
+
| align | "start" \| "center" \| "end" | "center" | Alignment relative to trigger |
|
|
77
|
+
| sideOffset | number | 4 | Distance from trigger in pixels |
|
|
78
|
+
| alignOffset | number | 0 | Offset along alignment axis in pixels |
|
|
79
|
+
| className | string | - | Additional CSS classes (default width is w-72) |
|
|
80
|
+
|
|
81
|
+
### PopoverHeader
|
|
82
|
+
|
|
83
|
+
Optional container for title and description with consistent spacing.
|
|
84
|
+
|
|
85
|
+
Standard `div` props.
|
|
86
|
+
|
|
87
|
+
### PopoverTitle
|
|
88
|
+
|
|
89
|
+
Heading label with ARIA attributes. Renders h2 element.
|
|
90
|
+
|
|
91
|
+
Standard Base UI Title props (className, render, etc).
|
|
92
|
+
|
|
93
|
+
### PopoverDescription
|
|
94
|
+
|
|
95
|
+
Optional description text styled with muted foreground.
|
|
96
|
+
|
|
97
|
+
Standard Base UI Description props (className, render, etc).
|
|
98
|
+
|
|
99
|
+
## Data Attributes
|
|
100
|
+
|
|
101
|
+
Available on PopoverContent for styling:
|
|
102
|
+
|
|
103
|
+
| Attribute | When Present |
|
|
104
|
+
|-----------|--------------|
|
|
105
|
+
| data-open | Popover is open |
|
|
106
|
+
| data-closed | Popover is closed |
|
|
107
|
+
| data-side | Value is current side (top/right/bottom/left) |
|
|
108
|
+
| data-starting-style | During opening animation |
|
|
109
|
+
| data-ending-style | During closing animation |
|
|
110
|
+
|
|
111
|
+
## Examples
|
|
112
|
+
|
|
113
|
+
### User Profile Preview
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
<Popover>
|
|
117
|
+
<PopoverTrigger>
|
|
118
|
+
<button className="flex items-center gap-2">
|
|
119
|
+
<Avatar />
|
|
120
|
+
<span>vitalik.eth</span>
|
|
121
|
+
</button>
|
|
122
|
+
</PopoverTrigger>
|
|
123
|
+
<PopoverContent className="w-80" side="bottom" align="start">
|
|
124
|
+
<div className="space-y-3">
|
|
125
|
+
<div className="flex items-start gap-3">
|
|
126
|
+
<Avatar size="lg" />
|
|
127
|
+
<div className="flex-1">
|
|
128
|
+
<p className="font-semibold">vitalik.eth</p>
|
|
129
|
+
<p className="text-muted-foreground text-sm">@vitalik</p>
|
|
130
|
+
</div>
|
|
131
|
+
<Button size="sm">Follow</Button>
|
|
132
|
+
</div>
|
|
133
|
+
<p className="text-sm">Creator of Ethereum...</p>
|
|
134
|
+
</div>
|
|
135
|
+
</PopoverContent>
|
|
136
|
+
</Popover>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Filter Form
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
function FilterPopover() {
|
|
143
|
+
const [open, setOpen] = useState(false)
|
|
144
|
+
const [dateRange, setDateRange] = useState("last-7-days")
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
148
|
+
<PopoverTrigger>
|
|
149
|
+
<Button variant="outline" size="sm">
|
|
150
|
+
<SettingsIcon className="mr-2 size-4" />
|
|
151
|
+
Filters
|
|
152
|
+
</Button>
|
|
153
|
+
</PopoverTrigger>
|
|
154
|
+
<PopoverContent className="w-80" side="bottom" align="end">
|
|
155
|
+
<PopoverHeader>
|
|
156
|
+
<PopoverTitle>Filter Options</PopoverTitle>
|
|
157
|
+
<PopoverDescription>
|
|
158
|
+
Customize the data displayed
|
|
159
|
+
</PopoverDescription>
|
|
160
|
+
</PopoverHeader>
|
|
161
|
+
<div className="space-y-4">
|
|
162
|
+
<div className="space-y-2">
|
|
163
|
+
<Label htmlFor="date-range">Date Range</Label>
|
|
164
|
+
<select
|
|
165
|
+
id="date-range"
|
|
166
|
+
value={dateRange}
|
|
167
|
+
onChange={(e) => setDateRange(e.target.value)}
|
|
168
|
+
>
|
|
169
|
+
<option value="last-7-days">Last 7 days</option>
|
|
170
|
+
<option value="last-30-days">Last 30 days</option>
|
|
171
|
+
</select>
|
|
172
|
+
</div>
|
|
173
|
+
<div className="flex justify-end gap-2">
|
|
174
|
+
<Button variant="ghost" size="sm" onClick={() => setOpen(false)}>
|
|
175
|
+
Cancel
|
|
176
|
+
</Button>
|
|
177
|
+
<Button size="sm" onClick={() => setOpen(false)}>
|
|
178
|
+
Apply
|
|
179
|
+
</Button>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</PopoverContent>
|
|
183
|
+
</Popover>
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Contextual Help
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
<div className="flex items-center gap-2">
|
|
192
|
+
<Label htmlFor="api-key">API Key</Label>
|
|
193
|
+
<Popover>
|
|
194
|
+
<PopoverTrigger>
|
|
195
|
+
<button className="text-muted-foreground hover:text-foreground">
|
|
196
|
+
<HelpCircleIcon className="size-4" />
|
|
197
|
+
</button>
|
|
198
|
+
</PopoverTrigger>
|
|
199
|
+
<PopoverContent className="w-80" side="right">
|
|
200
|
+
<PopoverHeader>
|
|
201
|
+
<PopoverTitle>About API Keys</PopoverTitle>
|
|
202
|
+
</PopoverHeader>
|
|
203
|
+
<div className="space-y-2 text-sm">
|
|
204
|
+
<p>API keys authenticate requests to the Neynar API...</p>
|
|
205
|
+
<ul className="text-muted-foreground ml-4 list-disc space-y-1">
|
|
206
|
+
<li>Production keys have higher rate limits</li>
|
|
207
|
+
<li>Development keys are for testing only</li>
|
|
208
|
+
</ul>
|
|
209
|
+
</div>
|
|
210
|
+
</PopoverContent>
|
|
211
|
+
</Popover>
|
|
212
|
+
</div>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Custom Trigger Element
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
<Popover>
|
|
219
|
+
<PopoverTrigger>
|
|
220
|
+
<Button variant="ghost" size="icon-sm">
|
|
221
|
+
<InfoIcon className="size-4" />
|
|
222
|
+
</Button>
|
|
223
|
+
</PopoverTrigger>
|
|
224
|
+
<PopoverContent className="w-80" side="left">
|
|
225
|
+
<PopoverHeader>
|
|
226
|
+
<PopoverTitle>Billing Information</PopoverTitle>
|
|
227
|
+
<PopoverDescription>
|
|
228
|
+
Your subscription details
|
|
229
|
+
</PopoverDescription>
|
|
230
|
+
</PopoverHeader>
|
|
231
|
+
<div className="space-y-3 text-sm">
|
|
232
|
+
<div className="flex justify-between">
|
|
233
|
+
<span className="text-muted-foreground">Current plan</span>
|
|
234
|
+
<span className="font-medium">Pro ($99/mo)</span>
|
|
235
|
+
</div>
|
|
236
|
+
<div className="flex justify-between">
|
|
237
|
+
<span className="text-muted-foreground">Next charge</span>
|
|
238
|
+
<span className="font-medium">$99.00</span>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</PopoverContent>
|
|
242
|
+
</Popover>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Hover Trigger
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
<Popover>
|
|
249
|
+
<PopoverTrigger openOnHover delay={200}>
|
|
250
|
+
<span className="underline decoration-dotted">Hover me</span>
|
|
251
|
+
</PopoverTrigger>
|
|
252
|
+
<PopoverContent side="top">
|
|
253
|
+
<p className="text-sm">This opens on hover with 200ms delay</p>
|
|
254
|
+
</PopoverContent>
|
|
255
|
+
</Popover>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Keyboard
|
|
259
|
+
|
|
260
|
+
| Key | Action |
|
|
261
|
+
|-----|--------|
|
|
262
|
+
| Escape | Close popover |
|
|
263
|
+
| Tab | Navigate focus within popover |
|
|
264
|
+
|
|
265
|
+
## Accessibility
|
|
266
|
+
|
|
267
|
+
- PopoverTitle automatically provides `aria-labelledby` for the popover
|
|
268
|
+
- PopoverDescription provides `aria-describedby` when present
|
|
269
|
+
- Focus is trapped within popover when `modal` is true or "trap-focus"
|
|
270
|
+
- Popover closes on Escape key press
|
|
271
|
+
- Focus returns to trigger when popover closes
|
|
272
|
+
|
|
273
|
+
## Related
|
|
274
|
+
|
|
275
|
+
- **Tooltip** - For simple text hints without interaction
|
|
276
|
+
- **Dropdown Menu** - For menus with selectable actions
|
|
277
|
+
- **Dialog** - For modal content requiring user action
|
|
278
|
+
- **Hover Card** - Similar to Popover but specifically for hover interactions
|