@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,228 @@
|
|
|
1
|
+
# ToggleGroup
|
|
2
|
+
|
|
3
|
+
A group of toggle buttons that share state, commonly used for formatting toolbars, view switchers, and filter controls.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { ToggleGroup, ToggleGroupItem } from "@neynar/ui/toggle-group"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<ToggleGroup>
|
|
15
|
+
<ToggleGroupItem value="option1">Option 1</ToggleGroupItem>
|
|
16
|
+
<ToggleGroupItem value="option2">Option 2</ToggleGroupItem>
|
|
17
|
+
<ToggleGroupItem value="option3">Option 3</ToggleGroupItem>
|
|
18
|
+
</ToggleGroup>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Components
|
|
22
|
+
|
|
23
|
+
| Component | Description |
|
|
24
|
+
|-----------|-------------|
|
|
25
|
+
| ToggleGroup | Root container that manages shared state and layout |
|
|
26
|
+
| ToggleGroupItem | Individual toggle button within the group |
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
### ToggleGroup
|
|
31
|
+
|
|
32
|
+
Inherits all props from `@base-ui/react/toggle-group` plus variant styling props.
|
|
33
|
+
|
|
34
|
+
| Prop | Type | Default | Description |
|
|
35
|
+
|------|------|---------|-------------|
|
|
36
|
+
| value | `any[]` | - | Controlled state: array of pressed item values |
|
|
37
|
+
| defaultValue | `any[]` | - | Uncontrolled initial state |
|
|
38
|
+
| onValueChange | `(value: any[]) => void` | - | Called when selection changes |
|
|
39
|
+
| multiple | `boolean` | `true` | Allow multiple items to be pressed |
|
|
40
|
+
| variant | `"default" \| "outline"` | - | Visual style inherited by all items |
|
|
41
|
+
| size | `"default" \| "sm" \| "lg"` | - | Size variant inherited by all items |
|
|
42
|
+
| spacing | `number` | `0` | Gap between items (0 = joined buttons) |
|
|
43
|
+
| orientation | `"horizontal" \| "vertical"` | `"horizontal"` | Layout direction |
|
|
44
|
+
| disabled | `boolean` | `false` | Disable all toggles in the group |
|
|
45
|
+
| loopFocus | `boolean` | `true` | Wrap focus when reaching end with arrow keys |
|
|
46
|
+
|
|
47
|
+
**Note:** By default, `multiple={true}` allows multiple selections. Set `multiple={false}` for single selection mode.
|
|
48
|
+
|
|
49
|
+
### ToggleGroupItem
|
|
50
|
+
|
|
51
|
+
Inherits variant and size from parent ToggleGroup context unless explicitly overridden.
|
|
52
|
+
|
|
53
|
+
| Prop | Type | Default | Description |
|
|
54
|
+
|------|------|---------|-------------|
|
|
55
|
+
| value | `string` | - | **Required.** Unique identifier for this item |
|
|
56
|
+
| variant | `"default" \| "outline"` | Inherits from group | Override group variant |
|
|
57
|
+
| size | `"default" \| "sm" \| "lg"` | Inherits from group | Override group size |
|
|
58
|
+
| aria-label | `string` | - | Required for icon-only buttons |
|
|
59
|
+
|
|
60
|
+
## Data Attributes
|
|
61
|
+
|
|
62
|
+
### ToggleGroup
|
|
63
|
+
|
|
64
|
+
| Attribute | When Present |
|
|
65
|
+
|-----------|--------------|
|
|
66
|
+
| data-orientation | Always: `"horizontal"` or `"vertical"` |
|
|
67
|
+
| data-disabled | Group is disabled |
|
|
68
|
+
| data-multiple | Multiple selection is enabled |
|
|
69
|
+
| data-spacing | Always: spacing value |
|
|
70
|
+
| data-variant | Always: variant name |
|
|
71
|
+
| data-size | Always: size name |
|
|
72
|
+
|
|
73
|
+
### ToggleGroupItem
|
|
74
|
+
|
|
75
|
+
| Attribute | When Present |
|
|
76
|
+
|-----------|--------------|
|
|
77
|
+
| data-pressed | Item is in pressed state |
|
|
78
|
+
| data-disabled | Item is disabled |
|
|
79
|
+
|
|
80
|
+
## Variants
|
|
81
|
+
|
|
82
|
+
### Visual Variants
|
|
83
|
+
|
|
84
|
+
| Variant | Appearance |
|
|
85
|
+
|---------|------------|
|
|
86
|
+
| default | Transparent background, fills on press |
|
|
87
|
+
| outline | Border with shadow, subtle background on press |
|
|
88
|
+
|
|
89
|
+
### Sizes
|
|
90
|
+
|
|
91
|
+
| Size | Height | Min Width | Padding |
|
|
92
|
+
|------|--------|-----------|---------|
|
|
93
|
+
| sm | 32px | 32px | 6px |
|
|
94
|
+
| default | 36px | 36px | 8px |
|
|
95
|
+
| lg | 40px | 40px | 10px |
|
|
96
|
+
|
|
97
|
+
## Examples
|
|
98
|
+
|
|
99
|
+
### Single Selection (Time Range Picker)
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
function TimeRangePicker() {
|
|
103
|
+
const [range, setRange] = useState(["7d"])
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<ToggleGroup
|
|
107
|
+
value={range}
|
|
108
|
+
onValueChange={(value) => {
|
|
109
|
+
if (value) setRange(value)
|
|
110
|
+
}}
|
|
111
|
+
variant="outline"
|
|
112
|
+
spacing={0}
|
|
113
|
+
>
|
|
114
|
+
<ToggleGroupItem value="1d">1D</ToggleGroupItem>
|
|
115
|
+
<ToggleGroupItem value="7d">7D</ToggleGroupItem>
|
|
116
|
+
<ToggleGroupItem value="30d">30D</ToggleGroupItem>
|
|
117
|
+
<ToggleGroupItem value="90d">90D</ToggleGroupItem>
|
|
118
|
+
</ToggleGroup>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Multiple Selection (Text Formatting)
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
function TextFormatting() {
|
|
127
|
+
return (
|
|
128
|
+
<ToggleGroup variant="outline" spacing={0}>
|
|
129
|
+
<ToggleGroupItem value="bold" aria-label="Bold">
|
|
130
|
+
<BoldIcon />
|
|
131
|
+
</ToggleGroupItem>
|
|
132
|
+
<ToggleGroupItem value="italic" aria-label="Italic">
|
|
133
|
+
<ItalicIcon />
|
|
134
|
+
</ToggleGroupItem>
|
|
135
|
+
<ToggleGroupItem value="underline" aria-label="Underline">
|
|
136
|
+
<UnderlineIcon />
|
|
137
|
+
</ToggleGroupItem>
|
|
138
|
+
</ToggleGroup>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### View Switcher (Icon-Only)
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
function ViewSwitcher() {
|
|
147
|
+
const [view, setView] = useState(["grid"])
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<ToggleGroup
|
|
151
|
+
value={view}
|
|
152
|
+
onValueChange={(value) => {
|
|
153
|
+
if (value) setView(value)
|
|
154
|
+
}}
|
|
155
|
+
variant="outline"
|
|
156
|
+
spacing={0}
|
|
157
|
+
>
|
|
158
|
+
<ToggleGroupItem value="grid" aria-label="Grid view">
|
|
159
|
+
<GridIcon />
|
|
160
|
+
</ToggleGroupItem>
|
|
161
|
+
<ToggleGroupItem value="list" aria-label="List view">
|
|
162
|
+
<ListIcon />
|
|
163
|
+
</ToggleGroupItem>
|
|
164
|
+
</ToggleGroup>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Vertical Layout with Spacing
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<ToggleGroup orientation="vertical" spacing={2} variant="outline">
|
|
173
|
+
<ToggleGroupItem value="option1">Option 1</ToggleGroupItem>
|
|
174
|
+
<ToggleGroupItem value="option2">Option 2</ToggleGroupItem>
|
|
175
|
+
<ToggleGroupItem value="option3">Option 3</ToggleGroupItem>
|
|
176
|
+
</ToggleGroup>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Separated Buttons (Spacing > 0)
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
<ToggleGroup variant="outline" spacing={4}>
|
|
183
|
+
<ToggleGroupItem value="filter1">Active</ToggleGroupItem>
|
|
184
|
+
<ToggleGroupItem value="filter2">Pending</ToggleGroupItem>
|
|
185
|
+
<ToggleGroupItem value="filter3">Archived</ToggleGroupItem>
|
|
186
|
+
</ToggleGroup>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Keyboard Navigation
|
|
190
|
+
|
|
191
|
+
| Key | Action |
|
|
192
|
+
|-----|--------|
|
|
193
|
+
| Tab | Focus the group (first/last item based on direction) |
|
|
194
|
+
| ArrowRight / ArrowDown | Move focus to next item |
|
|
195
|
+
| ArrowLeft / ArrowUp | Move focus to previous item |
|
|
196
|
+
| Space / Enter | Toggle the focused item |
|
|
197
|
+
| Home | Focus first item |
|
|
198
|
+
| End | Focus last item |
|
|
199
|
+
|
|
200
|
+
Arrow key direction depends on `orientation`: horizontal uses Left/Right, vertical uses Up/Down.
|
|
201
|
+
|
|
202
|
+
## Accessibility
|
|
203
|
+
|
|
204
|
+
- Uses `role="group"` for the container
|
|
205
|
+
- Each toggle uses `aria-pressed` to indicate state
|
|
206
|
+
- Icon-only buttons **must** include `aria-label`
|
|
207
|
+
- Keyboard navigation follows ARIA authoring practices
|
|
208
|
+
- Focus management automatically handles arrow key navigation
|
|
209
|
+
|
|
210
|
+
## Styling Notes
|
|
211
|
+
|
|
212
|
+
### Joined Buttons (spacing=0)
|
|
213
|
+
|
|
214
|
+
When `spacing={0}`, items are visually joined:
|
|
215
|
+
- First item keeps left border radius (or top for vertical)
|
|
216
|
+
- Middle items have no border radius
|
|
217
|
+
- Last item keeps right border radius (or bottom for vertical)
|
|
218
|
+
- Outline variant: middle items share borders (no duplicate borders)
|
|
219
|
+
|
|
220
|
+
### Context Inheritance
|
|
221
|
+
|
|
222
|
+
Items automatically inherit `variant` and `size` from the parent ToggleGroup via React context. You can override these per-item if needed.
|
|
223
|
+
|
|
224
|
+
## Related
|
|
225
|
+
|
|
226
|
+
- [Toggle](./toggle.llm.md) - Single toggle button
|
|
227
|
+
- [Button](./button.llm.md) - Standard button component
|
|
228
|
+
- [RadioGroup](./radio-group.llm.md) - Radio button groups
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Toggle
|
|
2
|
+
|
|
3
|
+
Two-state button that can be pressed (on) or unpressed (off).
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Toggle } from "@neynar/ui/toggle"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<Toggle>
|
|
15
|
+
<Icon />
|
|
16
|
+
Label
|
|
17
|
+
</Toggle>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
### Toggle
|
|
23
|
+
|
|
24
|
+
Extends `@base-ui/react/toggle` Props with additional variant styling.
|
|
25
|
+
|
|
26
|
+
| Prop | Type | Default | Description |
|
|
27
|
+
|------|------|---------|-------------|
|
|
28
|
+
| pressed | boolean | - | Controlled pressed state |
|
|
29
|
+
| defaultPressed | boolean | false | Uncontrolled default pressed state |
|
|
30
|
+
| onPressedChange | (pressed: boolean) => void | - | Called when pressed state changes |
|
|
31
|
+
| disabled | boolean | false | Whether toggle is disabled |
|
|
32
|
+
| variant | "default" \| "outline" | "default" | Visual style variant |
|
|
33
|
+
| size | "sm" \| "default" \| "lg" | "default" | Toggle size |
|
|
34
|
+
| children | ReactNode | - | Toggle content (icon, text, or both) |
|
|
35
|
+
| className | string | - | Additional CSS classes |
|
|
36
|
+
| render | ReactElement \| function | - | Custom render prop |
|
|
37
|
+
|
|
38
|
+
### Variant Details
|
|
39
|
+
|
|
40
|
+
**variant="default"**: Transparent background, shows pressed state with muted background.
|
|
41
|
+
|
|
42
|
+
**variant="outline"**: Border with shadow, more prominent visual separation.
|
|
43
|
+
|
|
44
|
+
## Data Attributes
|
|
45
|
+
|
|
46
|
+
| Attribute | When Present |
|
|
47
|
+
|-----------|--------------|
|
|
48
|
+
| data-pressed | Toggle is in pressed state |
|
|
49
|
+
| data-disabled | Toggle is disabled |
|
|
50
|
+
| aria-pressed | "true" or "false" based on state |
|
|
51
|
+
|
|
52
|
+
## Variants
|
|
53
|
+
|
|
54
|
+
| Variant | Options |
|
|
55
|
+
|---------|---------|
|
|
56
|
+
| variant | default, outline |
|
|
57
|
+
| size | sm, default, lg |
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
### Basic Toggle
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
function BasicExample() {
|
|
65
|
+
const [pressed, setPressed] = useState(false)
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Toggle
|
|
69
|
+
pressed={pressed}
|
|
70
|
+
onPressedChange={setPressed}
|
|
71
|
+
>
|
|
72
|
+
Toggle me
|
|
73
|
+
</Toggle>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Icon-Only Toggle
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { BoldIcon } from "lucide-react"
|
|
82
|
+
|
|
83
|
+
function IconToggle() {
|
|
84
|
+
return (
|
|
85
|
+
<Toggle aria-label="Toggle bold">
|
|
86
|
+
<BoldIcon />
|
|
87
|
+
</Toggle>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Icon with Text
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { GridIcon, ListIcon } from "lucide-react"
|
|
96
|
+
|
|
97
|
+
function ViewModeToggle() {
|
|
98
|
+
const [viewMode, setViewMode] = useState<"grid" | "list">("grid")
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className="flex gap-2">
|
|
102
|
+
<Toggle
|
|
103
|
+
pressed={viewMode === "grid"}
|
|
104
|
+
onPressedChange={(pressed) =>
|
|
105
|
+
pressed && setViewMode("grid")
|
|
106
|
+
}
|
|
107
|
+
aria-label="Grid view"
|
|
108
|
+
>
|
|
109
|
+
<GridIcon />
|
|
110
|
+
Grid
|
|
111
|
+
</Toggle>
|
|
112
|
+
<Toggle
|
|
113
|
+
pressed={viewMode === "list"}
|
|
114
|
+
onPressedChange={(pressed) =>
|
|
115
|
+
pressed && setViewMode("list")
|
|
116
|
+
}
|
|
117
|
+
aria-label="List view"
|
|
118
|
+
>
|
|
119
|
+
<ListIcon />
|
|
120
|
+
List
|
|
121
|
+
</Toggle>
|
|
122
|
+
</div>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Formatting Toolbar
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react"
|
|
131
|
+
|
|
132
|
+
function FormattingToolbar() {
|
|
133
|
+
const [formatting, setFormatting] = useState({
|
|
134
|
+
bold: false,
|
|
135
|
+
italic: false,
|
|
136
|
+
underline: false,
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div className="flex gap-2">
|
|
141
|
+
<Toggle
|
|
142
|
+
size="sm"
|
|
143
|
+
variant="outline"
|
|
144
|
+
pressed={formatting.bold}
|
|
145
|
+
onPressedChange={(pressed) =>
|
|
146
|
+
setFormatting((prev) => ({ ...prev, bold: pressed }))
|
|
147
|
+
}
|
|
148
|
+
aria-label="Toggle bold"
|
|
149
|
+
>
|
|
150
|
+
<BoldIcon />
|
|
151
|
+
</Toggle>
|
|
152
|
+
<Toggle
|
|
153
|
+
size="sm"
|
|
154
|
+
variant="outline"
|
|
155
|
+
pressed={formatting.italic}
|
|
156
|
+
onPressedChange={(pressed) =>
|
|
157
|
+
setFormatting((prev) => ({ ...prev, italic: pressed }))
|
|
158
|
+
}
|
|
159
|
+
aria-label="Toggle italic"
|
|
160
|
+
>
|
|
161
|
+
<ItalicIcon />
|
|
162
|
+
</Toggle>
|
|
163
|
+
<Toggle
|
|
164
|
+
size="sm"
|
|
165
|
+
variant="outline"
|
|
166
|
+
pressed={formatting.underline}
|
|
167
|
+
onPressedChange={(pressed) =>
|
|
168
|
+
setFormatting((prev) => ({ ...prev, underline: pressed }))
|
|
169
|
+
}
|
|
170
|
+
aria-label="Toggle underline"
|
|
171
|
+
>
|
|
172
|
+
<UnderlineIcon />
|
|
173
|
+
</Toggle>
|
|
174
|
+
</div>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Theme Toggle
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
import { SunIcon, MoonIcon } from "lucide-react"
|
|
183
|
+
|
|
184
|
+
function ThemeToggle() {
|
|
185
|
+
const [theme, setTheme] = useState<"light" | "dark">("light")
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<div className="flex gap-2">
|
|
189
|
+
<Toggle
|
|
190
|
+
variant="outline"
|
|
191
|
+
pressed={theme === "light"}
|
|
192
|
+
onPressedChange={(pressed) =>
|
|
193
|
+
pressed && setTheme("light")
|
|
194
|
+
}
|
|
195
|
+
aria-label="Light theme"
|
|
196
|
+
>
|
|
197
|
+
<SunIcon />
|
|
198
|
+
Light
|
|
199
|
+
</Toggle>
|
|
200
|
+
<Toggle
|
|
201
|
+
variant="outline"
|
|
202
|
+
pressed={theme === "dark"}
|
|
203
|
+
onPressedChange={(pressed) =>
|
|
204
|
+
pressed && setTheme("dark")
|
|
205
|
+
}
|
|
206
|
+
aria-label="Dark theme"
|
|
207
|
+
>
|
|
208
|
+
<MoonIcon />
|
|
209
|
+
Dark
|
|
210
|
+
</Toggle>
|
|
211
|
+
</div>
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Keyboard
|
|
217
|
+
|
|
218
|
+
| Key | Action |
|
|
219
|
+
|-----|--------|
|
|
220
|
+
| Space | Toggle pressed state |
|
|
221
|
+
| Enter | Toggle pressed state |
|
|
222
|
+
|
|
223
|
+
## Accessibility
|
|
224
|
+
|
|
225
|
+
- Renders semantic `<button>` element with `aria-pressed` attribute
|
|
226
|
+
- Icons automatically sized to 16px (size-4) unless custom size class provided
|
|
227
|
+
- Always provide `aria-label` when using icon-only toggles
|
|
228
|
+
- Disabled state prevents all interaction and reduces opacity
|
|
229
|
+
- Focus visible ring indicates keyboard focus
|
|
230
|
+
|
|
231
|
+
## Related
|
|
232
|
+
|
|
233
|
+
- [Button](./button.llm.md) - For actions instead of state toggles
|
|
234
|
+
- [Checkbox](./checkbox.llm.md) - For form selections
|
|
235
|
+
- [Switch](./switch.llm.md) - For on/off settings
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Tooltip
|
|
2
|
+
|
|
3
|
+
Displays contextual information on hover or focus.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Tooltip, TooltipTrigger, TooltipContent } from "@neynar/ui/tooltip"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<Tooltip>
|
|
15
|
+
<TooltipTrigger>Hover me</TooltipTrigger>
|
|
16
|
+
<TooltipContent>Helpful information</TooltipContent>
|
|
17
|
+
</Tooltip>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Components
|
|
21
|
+
|
|
22
|
+
| Component | Description |
|
|
23
|
+
|-----------|-------------|
|
|
24
|
+
| Tooltip | Root container, manages open state automatically |
|
|
25
|
+
| TooltipTrigger | Element that shows tooltip on hover/focus |
|
|
26
|
+
| TooltipContent | Popup content with automatic portal, positioning, and arrow |
|
|
27
|
+
| TooltipProvider | Optional provider for configuring shared delay (auto-included in Tooltip) |
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
### Tooltip
|
|
32
|
+
|
|
33
|
+
| Prop | Type | Default | Description |
|
|
34
|
+
|------|------|---------|-------------|
|
|
35
|
+
| defaultOpen | boolean | - | Whether tooltip is initially open (uncontrolled) |
|
|
36
|
+
| open | boolean | - | Controlled open state |
|
|
37
|
+
| onOpenChange | (open: boolean) => void | - | Called when open state changes |
|
|
38
|
+
| trackCursorAxis | 'none' \| 'both' \| 'x' \| 'y' | 'none' | Which axis the tooltip should track the cursor on |
|
|
39
|
+
|
|
40
|
+
### TooltipTrigger
|
|
41
|
+
|
|
42
|
+
Standard trigger props with `render` prop support. Use `render` to customize:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<TooltipTrigger render={<Button variant="ghost" size="icon" />}>
|
|
46
|
+
<SettingsIcon />
|
|
47
|
+
</TooltipTrigger>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### TooltipContent
|
|
51
|
+
|
|
52
|
+
Automatically renders portal with positioner and arrow.
|
|
53
|
+
|
|
54
|
+
| Prop | Type | Default | Description |
|
|
55
|
+
|------|------|---------|-------------|
|
|
56
|
+
| side | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' | Which side to position tooltip |
|
|
57
|
+
| sideOffset | number | 4 | Distance from trigger in pixels |
|
|
58
|
+
| align | 'start' \| 'center' \| 'end' | 'center' | How to align tooltip relative to side |
|
|
59
|
+
| alignOffset | number | 0 | Offset along alignment axis in pixels |
|
|
60
|
+
| className | string | - | Additional CSS classes |
|
|
61
|
+
|
|
62
|
+
### TooltipProvider
|
|
63
|
+
|
|
64
|
+
Only needed when sharing state across multiple tooltips. Tooltip automatically includes provider.
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Default | Description |
|
|
67
|
+
|------|------|---------|-------------|
|
|
68
|
+
| delay | number | 0 | Delay in ms before showing tooltips |
|
|
69
|
+
|
|
70
|
+
## Data Attributes (for styling)
|
|
71
|
+
|
|
72
|
+
| Attribute | When Present |
|
|
73
|
+
|-----------|--------------|
|
|
74
|
+
| data-open | Tooltip is open |
|
|
75
|
+
| data-closed | Tooltip is closed |
|
|
76
|
+
| data-side | Current side: 'top' \| 'bottom' \| 'left' \| 'right' |
|
|
77
|
+
| data-align | Current alignment: 'start' \| 'center' \| 'end' |
|
|
78
|
+
| data-starting-style | Tooltip is animating in |
|
|
79
|
+
| data-ending-style | Tooltip is animating out |
|
|
80
|
+
| data-instant | Animations should be instant |
|
|
81
|
+
|
|
82
|
+
## Examples
|
|
83
|
+
|
|
84
|
+
### Basic Usage
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
<Tooltip>
|
|
88
|
+
<TooltipTrigger>
|
|
89
|
+
<Button variant="outline">Hover me</Button>
|
|
90
|
+
</TooltipTrigger>
|
|
91
|
+
<TooltipContent>
|
|
92
|
+
<p>This is a tooltip</p>
|
|
93
|
+
</TooltipContent>
|
|
94
|
+
</Tooltip>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Icon Button with Tooltip
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<Tooltip>
|
|
101
|
+
<TooltipTrigger>
|
|
102
|
+
<Button variant="ghost" size="icon">
|
|
103
|
+
<SettingsIcon />
|
|
104
|
+
</Button>
|
|
105
|
+
</TooltipTrigger>
|
|
106
|
+
<TooltipContent>
|
|
107
|
+
<p>Settings</p>
|
|
108
|
+
</TooltipContent>
|
|
109
|
+
</Tooltip>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Placement Options
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<Tooltip>
|
|
116
|
+
<TooltipTrigger>
|
|
117
|
+
<Button>Show below</Button>
|
|
118
|
+
</TooltipTrigger>
|
|
119
|
+
<TooltipContent side="bottom" align="start">
|
|
120
|
+
<p>Positioned at bottom-start</p>
|
|
121
|
+
</TooltipContent>
|
|
122
|
+
</Tooltip>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### With Keyboard Shortcut
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
<Tooltip>
|
|
129
|
+
<TooltipTrigger>
|
|
130
|
+
<Button variant="outline">Save</Button>
|
|
131
|
+
</TooltipTrigger>
|
|
132
|
+
<TooltipContent>
|
|
133
|
+
<div className="flex items-center gap-2">
|
|
134
|
+
<span>Save document</span>
|
|
135
|
+
<kbd className="bg-background text-foreground rounded border px-1.5 py-0.5 font-mono text-xs">
|
|
136
|
+
⌘S
|
|
137
|
+
</kbd>
|
|
138
|
+
</div>
|
|
139
|
+
</TooltipContent>
|
|
140
|
+
</Tooltip>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Help Icon with Detailed Info
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
<Tooltip>
|
|
147
|
+
<TooltipTrigger>
|
|
148
|
+
<button className="text-muted-foreground hover:text-foreground inline-flex items-center transition-colors">
|
|
149
|
+
<HelpCircleIcon className="size-4" />
|
|
150
|
+
</button>
|
|
151
|
+
</TooltipTrigger>
|
|
152
|
+
<TooltipContent side="top">
|
|
153
|
+
<p className="max-w-xs">
|
|
154
|
+
Track your API requests, rate limits, and usage patterns across all your applications.
|
|
155
|
+
</p>
|
|
156
|
+
</TooltipContent>
|
|
157
|
+
</Tooltip>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Always Open (Controlled)
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
<Tooltip defaultOpen>
|
|
164
|
+
<TooltipTrigger>
|
|
165
|
+
<Button variant="outline">Always visible</Button>
|
|
166
|
+
</TooltipTrigger>
|
|
167
|
+
<TooltipContent>
|
|
168
|
+
<p>This tooltip is always visible</p>
|
|
169
|
+
</TooltipContent>
|
|
170
|
+
</Tooltip>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Keyboard
|
|
174
|
+
|
|
175
|
+
| Key | Action |
|
|
176
|
+
|-----|--------|
|
|
177
|
+
| Tab | Move focus to/from trigger |
|
|
178
|
+
| Escape | Close tooltip |
|
|
179
|
+
|
|
180
|
+
## Accessibility
|
|
181
|
+
|
|
182
|
+
- Automatically adds ARIA attributes for screen readers
|
|
183
|
+
- Tooltip appears on hover and focus for keyboard users
|
|
184
|
+
- Content announced to screen readers when opened
|
|
185
|
+
- Works with disabled elements (tooltip still shows)
|
|
186
|
+
- Arrow provides visual relationship between trigger and content
|
|
187
|
+
|
|
188
|
+
## Related
|
|
189
|
+
|
|
190
|
+
- [Popover](./popover.llm.md) - For interactive content requiring click to open
|
|
191
|
+
- [HoverCard](./hover-card.llm.md) - For rich preview content on hover
|