@telegraph/combobox 0.1.0 → 0.1.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/README.md CHANGED
@@ -1,35 +1,45 @@
1
- ![Telegraph by Knock](https://github.com/knocklabs/telegraph/assets/29106675/9b5022e3-b02c-4582-ba57-3d6171e45e44)
1
+ # 🔍 Combobox
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@telegraph/button.svg)](https://www.npmjs.com/package/@telegraph/combobox)
3
+ > A searchable select component combining input and dropdown functionality with single and multi-select support.
4
4
 
5
- # @telegraph/combobox
5
+ ![Telegraph by Knock](https://github.com/knocklabs/telegraph/assets/29106675/9b5022e3-b02c-4582-ba57-3d6171e45e44)
6
6
 
7
- > A styled menu, triggered by a Select, that combines an Input and Single- or Multi-select.
7
+ [![npm version](https://img.shields.io/npm/v/@telegraph/combobox.svg)](https://www.npmjs.com/package/@telegraph/combobox)
8
+ [![minzipped size](https://img.shields.io/bundlephobia/minzip/@telegraph/combobox)](https://bundlephobia.com/result?p=@telegraph/combobox)
9
+ [![license](https://img.shields.io/npm/l/@telegraph/combobox)](https://github.com/knocklabs/telegraph/blob/main/LICENSE)
8
10
 
9
- ## Installation Instructions
11
+ ## Installation
10
12
 
11
- ```
13
+ ```bash
12
14
  npm install @telegraph/combobox
13
15
  ```
14
16
 
15
17
  ### Add stylesheet
16
18
 
17
- ```
18
- @import "@telegraph/combobox"
19
+ Pick one:
20
+
21
+ Via CSS (preferred):
22
+
23
+ ```css
24
+ @import "@telegraph/combobox";
19
25
  ```
20
26
 
21
- ### Basic Usage
27
+ Via Javascript:
22
28
 
23
- A combobox component that combines input and select functionality with a searchable dropdown menu.
29
+ ```tsx
30
+ import "@telegraph/combobox/default.css";
31
+ ```
32
+
33
+ > Then, include `className="tgph"` on the farthest parent element wrapping the telegraph components
24
34
 
25
- #### `<Combobox/>`
35
+ ## Quick Start
26
36
 
27
37
  ```tsx
28
38
  import { Combobox } from "@telegraph/combobox";
29
39
  import { useState } from "react";
30
40
 
31
41
  // Single select example
32
- const SingleSelectExample = () => {
42
+ export const SingleSelectExample = () => {
33
43
  const [value, setValue] = useState<string>("");
34
44
 
35
45
  return (
@@ -45,98 +55,72 @@ const SingleSelectExample = () => {
45
55
  </Combobox.Root>
46
56
  );
47
57
  };
48
-
49
- // Multi select example
50
- const MultiSelectExample = () => {
51
- const [values, setValues] = useState<string[]>([]);
52
-
53
- return (
54
- <Combobox.Root value={values} onValueChange={setValues}>
55
- <Combobox.Trigger placeholder="Select options..." />
56
- <Combobox.Content>
57
- <Combobox.Search />
58
- <Combobox.Options>
59
- <Combobox.Option value="option1">Option 1</Combobox.Option>
60
- <Combobox.Option value="option2">Option 2</Combobox.Option>
61
- </Combobox.Options>
62
- </Combobox.Content>
63
- </Combobox.Root>
64
- );
65
- };
66
58
  ```
67
59
 
68
- ### Type Examples
69
-
70
- #### Single Select Types
60
+ ## API Reference
71
61
 
72
- ```tsx
73
- // String values (recommended)
74
- const [value, setValue] = useState<string>("");
75
- ```
62
+ ### `<Combobox.Root>`
76
63
 
77
- #### Multi Select Types
64
+ The root component that manages the state and context for the combobox.
78
65
 
79
- ```tsx
80
- // String array values (recommended)
81
- const [values, setValues] = useState<string[]>([]);
82
- ```
66
+ | Prop | Type | Default | Description |
67
+ | ---------------- | ----------------------------------------------------------- | ------------ | -------------------------------------- |
68
+ | `value` | `string \| string[] \| Option \| Option[]` | `undefined` | The selected value(s) |
69
+ | `onValueChange` | `(value: string \| string[] \| Option \| Option[]) => void` | `undefined` | Callback when selection changes |
70
+ | `layout` | `"truncate" \| "wrap"` | `"truncate"` | How to display multiple selections |
71
+ | `open` | `boolean` | `undefined` | Controlled open state |
72
+ | `defaultOpen` | `boolean` | `false` | Initial open state |
73
+ | `errored` | `boolean` | `false` | Shows error styling |
74
+ | `placeholder` | `string` | `undefined` | Placeholder text |
75
+ | `onOpenChange` | `(open: boolean) => void` | `undefined` | Callback when open state changes |
76
+ | `modal` | `boolean` | `true` | Whether to render in a modal |
77
+ | `closeOnSelect` | `boolean` | `true` | Close menu after selection |
78
+ | `clearable` | `boolean` | `false` | Show clear button |
79
+ | `disabled` | `boolean` | `false` | Disable the combobox |
80
+ | `legacyBehavior` | `boolean` | `false` | Use legacy object format ⚠️ Deprecated |
81
+
82
+ ### `<Combobox.Trigger>`
83
83
 
84
- ### Accessibility
84
+ The button that triggers the combobox dropdown.
85
85
 
86
- The combobox implements the [ARIA Combobox Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/), providing:
86
+ | Prop | Type | Default | Description |
87
+ | ------------- | ------------------- | ----------- | ---------------------- |
88
+ | `size` | `"1" \| "2" \| "3"` | `"2"` | Size of the trigger |
89
+ | `placeholder` | `string` | `undefined` | Placeholder text |
90
+ | `children` | `ReactNode` | `undefined` | Custom trigger content |
87
91
 
88
- - Proper ARIA roles and attributes
89
- - Keyboard navigation:
90
- - `↓` / `↑`: Navigate options
91
- - `Enter` / `Space`: Select option
92
- - `Escape`: Close dropdown
93
- - `Tab`: Move focus
94
- - Screen reader announcements for selection changes
95
- - Focus management
92
+ ### Other Components
96
93
 
97
- ### Common Patterns
94
+ - **`<Combobox.Content>`** - Dropdown menu content container
95
+ - **`<Combobox.Options>`** - Container for option items
96
+ - **`<Combobox.Option>`** - Individual selectable option
97
+ - **`<Combobox.Search>`** - Search input for filtering options
98
+ - **`<Combobox.Empty>`** - Empty state when no options match
99
+ - **`<Combobox.Create>`** - Option to create new values
98
100
 
99
- #### Form Integration
101
+ For detailed props of each component, see the [Complete Component Reference](#complete-component-reference) section below.
100
102
 
101
- ```tsx
102
- import { useForm } from "react-hook-form";
103
+ ## Advanced Usage
103
104
 
104
- const MyForm = () => {
105
- const { register, setValue } = useForm();
106
-
107
- return (
108
- <form>
109
- <Combobox.Root onValueChange={(value) => setValue("field", value)}>
110
- {/* ... */}
111
- </Combobox.Root>
112
- </form>
113
- );
114
- };
115
- ```
116
-
117
- #### Custom Filtering
105
+ ### Multi-Select with Tags
118
106
 
119
107
  ```tsx
120
- const MyCombobox = () => {
121
- const [searchQuery, setSearchQuery] = useState("");
122
- const options = useMemo(
123
- () =>
124
- allOptions.filter((opt) =>
125
- opt.toLowerCase().includes(searchQuery.toLowerCase()),
126
- ),
127
- [searchQuery],
128
- );
108
+ import { Combobox } from "@telegraph/combobox";
109
+ import { useState } from "react";
110
+
111
+ export const MultiSelectExample = () => {
112
+ const [values, setValues] = useState<string[]>([]);
129
113
 
130
114
  return (
131
- <Combobox.Root>
115
+ <Combobox.Root value={values} onValueChange={setValues} clearable>
116
+ <Combobox.Trigger placeholder="Select multiple options..." />
132
117
  <Combobox.Content>
133
- <Combobox.Search value={searchQuery} onValueChange={setSearchQuery} />
118
+ <Combobox.Search />
134
119
  <Combobox.Options>
135
- {options.map((opt) => (
136
- <Combobox.Option key={opt} value={opt}>
137
- {opt}
138
- </Combobox.Option>
139
- ))}
120
+ <Combobox.Option value="react">React</Combobox.Option>
121
+ <Combobox.Option value="vue">Vue</Combobox.Option>
122
+ <Combobox.Option value="svelte">Svelte</Combobox.Option>
123
+ <Combobox.Option value="angular">Angular</Combobox.Option>
140
124
  </Combobox.Options>
141
125
  </Combobox.Content>
142
126
  </Combobox.Root>
@@ -144,329 +128,275 @@ const MyCombobox = () => {
144
128
  };
145
129
  ```
146
130
 
147
- #### Async Loading
131
+ ### Async Loading with Search
148
132
 
149
133
  ```tsx
150
- const AsyncCombobox = () => {
134
+ import { Combobox } from "@telegraph/combobox";
135
+ import { Box } from "@telegraph/layout";
136
+ import { useMemo, useState } from "react";
137
+
138
+ export const AsyncCombobox = () => {
151
139
  const [isLoading, setIsLoading] = useState(false);
152
- const [options, setOptions] = useState([]);
140
+ const [options, setOptions] = useState<string[]>([]);
141
+ const [searchQuery, setSearchQuery] = useState("");
153
142
 
154
- const loadOptions = async (query) => {
143
+ const loadOptions = async (query: string) => {
155
144
  setIsLoading(true);
156
- const results = await fetchOptions(query);
157
- setOptions(results);
158
- setIsLoading(false);
145
+ try {
146
+ const results = await fetchOptions(query);
147
+ setOptions(results);
148
+ } finally {
149
+ setIsLoading(false);
150
+ }
159
151
  };
160
152
 
153
+ const filteredOptions = useMemo(() => {
154
+ return options.filter((option) =>
155
+ option.toLowerCase().includes(searchQuery.toLowerCase()),
156
+ );
157
+ }, [options, searchQuery]);
158
+
161
159
  return (
162
160
  <Combobox.Root>
161
+ <Combobox.Trigger placeholder="Search for options..." />
163
162
  <Combobox.Content>
164
- <Combobox.Search onValueChange={loadOptions} />
163
+ <Combobox.Search
164
+ value={searchQuery}
165
+ onValueChange={(query) => {
166
+ setSearchQuery(query);
167
+ loadOptions(query);
168
+ }}
169
+ />
165
170
  <Combobox.Options>
166
171
  {isLoading ? (
167
- <Box p="4" textAlign="center">
172
+ <Box padding="4" textAlign="center">
168
173
  Loading...
169
174
  </Box>
170
175
  ) : (
171
- options.map((opt) => (
172
- <Combobox.Option key={opt} value={opt}>
173
- {opt}
176
+ filteredOptions.map((option) => (
177
+ <Combobox.Option key={option} value={option}>
178
+ {option}
174
179
  </Combobox.Option>
175
180
  ))
176
181
  )}
177
182
  </Combobox.Options>
183
+ <Combobox.Empty />
178
184
  </Combobox.Content>
179
185
  </Combobox.Root>
180
186
  );
181
187
  };
182
188
  ```
183
189
 
184
- #### Error States
190
+ ### Create New Options
185
191
 
186
192
  ```tsx
187
- const ErrorCombobox = () => {
188
- const [error, setError] = useState("");
193
+ import { Combobox } from "@telegraph/combobox";
194
+ import { useState } from "react";
195
+
196
+ export const CreatableCombobox = () => {
197
+ const [options, setOptions] = useState(["Option 1", "Option 2"]);
198
+ const [value, setValue] = useState("");
199
+
200
+ const handleCreate = (newValue: string) => {
201
+ setOptions((prev) => [...prev, newValue]);
202
+ setValue(newValue);
203
+ };
189
204
 
190
205
  return (
191
- <Stack gap="1">
192
- <Combobox.Root errored={!!error}>{/* ... */}</Combobox.Root>
193
- {error && (
194
- <Text color="red" size="1">
195
- {error}
196
- </Text>
197
- )}
198
- </Stack>
206
+ <Combobox.Root value={value} onValueChange={setValue}>
207
+ <Combobox.Trigger placeholder="Type to create..." />
208
+ <Combobox.Content>
209
+ <Combobox.Search />
210
+ <Combobox.Options>
211
+ {options.map((option) => (
212
+ <Combobox.Option key={option} value={option}>
213
+ {option}
214
+ </Combobox.Option>
215
+ ))}
216
+ </Combobox.Options>
217
+ <Combobox.Create
218
+ values={options}
219
+ onCreate={handleCreate}
220
+ leadingText="Create"
221
+ />
222
+ </Combobox.Content>
223
+ </Combobox.Root>
199
224
  );
200
225
  };
201
226
  ```
202
227
 
203
- ### Component Parts
228
+ ### Form Integration
204
229
 
205
- #### `<Combobox.Root/>`
230
+ ```tsx
231
+ import { Combobox } from "@telegraph/combobox";
232
+ import { useForm } from "react-hook-form";
206
233
 
207
- The root component that manages the state and context for the combobox.
234
+ type FormData = {
235
+ framework: string;
236
+ languages: string[];
237
+ };
208
238
 
209
- ##### Props
210
-
211
- | Name | Type | Default | Description |
212
- | -------------- | --------------------------------------------------------- | ---------- | ---------------------------------- |
213
- | value | string \| string[] \| Option \| Option[] | undefined | The selected value(s) |
214
- | onValueChange | (value: string \| string[] \| Option \| Option[]) => void | undefined | Callback when selection changes |
215
- | layout | "truncate" \| "wrap" | "truncate" | How to display multiple selections |
216
- | open | boolean | undefined | Controlled open state |
217
- | defaultOpen | boolean | false | Initial open state |
218
- | errored | boolean | false | Shows error styling |
219
- | placeholder | string | undefined | Placeholder text |
220
- | onOpenChange | (open: boolean) => void | undefined | Callback when open state changes |
221
- | modal | boolean | true | Whether to render in a modal |
222
- | closeOnSelect | boolean | true | Close menu after selection |
223
- | clearable | boolean | false | Show clear button |
224
- | disabled | boolean | false | Disable the combobox |
225
- | legacyBehavior | boolean | false | Use legacy object format |
226
-
227
- #### `<Combobox.Trigger/>`
239
+ export const FormIntegration = () => {
240
+ const { register, setValue, watch } = useForm<FormData>();
228
241
 
229
- The button that triggers the combobox dropdown.
242
+ return (
243
+ <form>
244
+ <Combobox.Root
245
+ value={watch("framework")}
246
+ onValueChange={(value) => setValue("framework", value)}
247
+ >
248
+ <Combobox.Trigger placeholder="Select framework..." />
249
+ <Combobox.Content>
250
+ <Combobox.Search />
251
+ <Combobox.Options>
252
+ <Combobox.Option value="react">React</Combobox.Option>
253
+ <Combobox.Option value="vue">Vue</Combobox.Option>
254
+ </Combobox.Options>
255
+ </Combobox.Content>
256
+ </Combobox.Root>
257
+ </form>
258
+ );
259
+ };
260
+ ```
230
261
 
231
- For advanced customization of the trigger's internal components (indicator, clear button, text display, etc.), see the [Trigger Primitives](#trigger-primitives) section below.
262
+ ### Custom Trigger with Primitives
232
263
 
233
- ##### Props
264
+ ```tsx
265
+ import { Combobox } from "@telegraph/combobox";
266
+ import { Box, Stack } from "@telegraph/layout";
267
+
268
+ export const CustomTrigger = () => (
269
+ <Combobox.Root clearable>
270
+ <Combobox.Trigger>
271
+ <Stack direction="row" justify="space-between" align="center" w="full">
272
+ <Box flex="1" overflow="hidden">
273
+ <Combobox.Primitives.TriggerTagsContainer>
274
+ <Combobox.Primitives.TriggerTag.Default value="tag1" />
275
+ <Combobox.Primitives.TriggerTag.Default value="tag2" />
276
+ </Combobox.Primitives.TriggerTagsContainer>
277
+ </Box>
278
+ <Stack direction="row" gap="1" align="center">
279
+ <Combobox.Primitives.TriggerClear />
280
+ <Box borderLeft="1" h="4" />
281
+ <Combobox.Primitives.TriggerIndicator />
282
+ </Stack>
283
+ </Stack>
284
+ </Combobox.Trigger>
285
+ <Combobox.Content>{/* Content */}</Combobox.Content>
286
+ </Combobox.Root>
287
+ );
288
+ ```
234
289
 
235
- | Name | Type | Default | Description |
236
- | ----------- | ----------------- | --------- | ---------------------- |
237
- | size | "1" \| "2" \| "3" | "2" | Size of the trigger |
238
- | placeholder | string | undefined | Placeholder text |
239
- | children | ReactNode | undefined | Custom trigger content |
290
+ ## Accessibility
240
291
 
241
- #### `<Combobox.Content/>`
292
+ - ✅ **ARIA Compliance**: Implements [ARIA Combobox Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/)
293
+ - ✅ **Keyboard Navigation**: Full keyboard support with arrow keys, Enter, Escape
294
+ - ✅ **Screen Readers**: Proper ARIA roles, labels, and state announcements
295
+ - ✅ **Focus Management**: Logical focus order and focus restoration
242
296
 
243
- The dropdown menu content container.
297
+ ### Keyboard Shortcuts
244
298
 
245
- ##### Props
299
+ | Key | Action |
300
+ | ----------------- | ------------------------------ |
301
+ | `↓` / `↑` | Navigate options |
302
+ | `Enter` / `Space` | Select option |
303
+ | `Escape` | Close dropdown |
304
+ | `Tab` | Move focus |
305
+ | `Backspace` | Remove last tag (multi-select) |
246
306
 
247
- Accepts all props from `TelegraphMenu.Content`
307
+ ### ARIA Attributes
248
308
 
249
- #### `<Combobox.Options/>`
309
+ - `role="combobox"` - On trigger element
310
+ - `aria-expanded` - Indicates dropdown state
311
+ - `aria-controls` - Links trigger to dropdown
312
+ - `aria-selected` - Indicates selected options
313
+ - `role="listbox"` and `role="option"` - On dropdown and options
250
314
 
251
- Container for the option items.
315
+ ### Best Practices
252
316
 
253
- ##### Props
317
+ 1. **Provide labels**: Use clear, descriptive placeholders
318
+ 2. **Handle loading states**: Show loading indicators during async operations
319
+ 3. **Error feedback**: Use the `errored` prop and provide error messages
320
+ 4. **Reasonable limits**: Consider pagination for large option lists
254
321
 
255
- Accepts all props from `Stack` component
322
+ ## Complete Component Reference
256
323
 
257
- #### `<Combobox.Option/>`
324
+ ### `<Combobox.Option>`
258
325
 
259
326
  Individual selectable option item.
260
327
 
261
- ##### Props
262
-
263
- | Name | Type | Default | Description |
264
- | -------- | ------- | --------- | -------------------- |
265
- | value | string | required | Option value |
266
- | label | string | undefined | Display label |
267
- | selected | boolean | undefined | Force selected state |
328
+ | Prop | Type | Default | Description |
329
+ | ---------- | --------- | ----------- | -------------------- |
330
+ | `value` | `string` | required | Option value |
331
+ | `label` | `string` | `undefined` | Display label |
332
+ | `selected` | `boolean` | `undefined` | Force selected state |
268
333
 
269
- #### `<Combobox.Search/>`
334
+ ### `<Combobox.Search>`
270
335
 
271
336
  Search input field for filtering options.
272
337
 
273
- ##### Props
338
+ | Prop | Type | Default | Description |
339
+ | ------------- | -------- | ---------- | ------------------- |
340
+ | `label` | `string` | `"Search"` | Accessibility label |
341
+ | `placeholder` | `string` | `"Search"` | Input placeholder |
274
342
 
275
- | Name | Type | Default | Description |
276
- | ----------- | ------ | -------- | ------------------- |
277
- | label | string | "Search" | Accessibility label |
278
- | placeholder | string | "Search" | Input placeholder |
279
-
280
- #### `<Combobox.Empty/>`
343
+ ### `<Combobox.Empty>`
281
344
 
282
345
  Empty state component shown when no options match search.
283
346
 
284
- ##### Props
285
-
286
- | Name | Type | Default | Description |
287
- | ------- | ----------------- | ------------------ | ------------------- |
288
- | icon | IconProps \| null | SearchIcon | Empty state icon |
289
- | message | string \| null | "No results found" | Empty state message |
347
+ | Prop | Type | Default | Description |
348
+ | --------- | ------------------- | -------------------- | ------------------- |
349
+ | `icon` | `IconProps \| null` | `SearchIcon` | Empty state icon |
350
+ | `message` | `string \| null` | `"No results found"` | Empty state message |
290
351
 
291
- #### `<Combobox.Create/>`
352
+ ### `<Combobox.Create>`
292
353
 
293
354
  Option to create new values when none match search.
294
355
 
295
- ##### Props
296
-
297
- | Name | Type | Default | Description |
298
- | ----------- | --------------------------------- | --------- | ------------------------ |
299
- | leadingText | string | "Create" | Text before search value |
300
- | values | string[] \| Option[] | undefined | Existing values |
301
- | onCreate | (value: string \| Option) => void | undefined | Creation callback |
356
+ | Prop | Type | Default | Description |
357
+ | ------------- | ----------------------------------- | ----------- | ------------------------ |
358
+ | `leadingText` | `string` | `"Create"` | Text before search value |
359
+ | `values` | `string[] \| Option[]` | `undefined` | Existing values |
360
+ | `onCreate` | `(value: string \| Option) => void` | `undefined` | Creation callback |
302
361
 
303
362
  ### Primitives
304
363
 
305
- The combobox includes several primitive components for advanced customization. These primitives allow you to build custom trigger layouts and behaviors while maintaining the combobox's core functionality.
364
+ The combobox includes primitive components for advanced customization:
306
365
 
307
366
  #### Trigger Primitives
308
367
 
309
- ##### `<Combobox.Primitives.TriggerIndicator/>`
310
-
311
- The dropdown chevron icon that rotates based on the combobox's open state.
312
-
313
- ###### Props
314
-
315
- | Name | Type | Default | Description |
316
- | ----------- | --------- | ----------- | ----------------------------------- |
317
- | icon | IconProps | ChevronDown | The icon to display |
318
- | aria-hidden | boolean | true | Whether to hide from screen readers |
319
-
320
- ```tsx
321
- <Combobox.Primitives.TriggerIndicator icon={CustomIcon} aria-hidden={false} />
322
- ```
323
-
324
- ##### `<Combobox.Primitives.TriggerClear/>`
325
-
326
- A button to clear the current selection(s). Only shown when `clearable` is true and there are selections.
327
-
328
- ###### Props
329
-
330
- | Name | Type | Default | Description |
331
- | ------------ | ---------------------------------- | --------- | --------------------- |
332
- | tooltipProps | TgphComponentProps<typeof Tooltip> | undefined | Props for the tooltip |
333
-
334
- Accepts all props from `Button`
335
-
336
- ```tsx
337
- <Combobox.Primitives.TriggerClear tooltipProps={{ delay: 300 }} />
338
- ```
339
-
340
- ##### `<Combobox.Primitives.TriggerText/>`
341
-
342
- Displays the selected value's text or label. Used in single-select mode.
343
-
344
- ###### Props
345
-
346
- Accepts all props from `Button.Text`
347
-
348
- ```tsx
349
- <Combobox.Primitives.TriggerText color="blue" weight="medium" />
350
- ```
351
-
352
- ##### `<Combobox.Primitives.TriggerPlaceholder/>`
353
-
354
- Shows placeholder text when no value is selected.
355
-
356
- ###### Props
357
-
358
- Accepts all props from `Button.Text`
359
-
360
- ```tsx
361
- <Combobox.Primitives.TriggerPlaceholder color="gray-8" />
362
- ```
363
-
364
- ##### `<Combobox.Primitives.TriggerTagsContainer/>`
365
-
366
- Container for selected value tags in multi-select mode. Handles tag layout and truncation.
367
-
368
- ###### Props
369
-
370
- Accepts all props from `Stack`
371
-
372
- ```tsx
373
- <Combobox.Primitives.TriggerTagsContainer gap="2" wrap="wrap" />
374
- ```
375
-
376
- ##### `<Combobox.Primitives.TriggerTag/>`
377
-
378
- A collection of components for building custom tags in multi-select mode:
379
-
380
- ###### `<Combobox.Primitives.TriggerTag.Root/>`
381
-
382
- The base container for a tag.
383
-
384
- Props:
385
- | Name | Type | Default | Description |
386
- | ---- | ---- | ------- | ----------- |
387
- | value | string | required | The value this tag represents |
388
-
389
- ###### `<Combobox.Primitives.TriggerTag.Text/>`
390
-
391
- The text content of a tag.
392
-
393
- Props: Accepts all props from `Text`
394
-
395
- ###### `<Combobox.Primitives.TriggerTag.Button/>`
396
-
397
- The remove button for a tag.
398
-
399
- Props: Accepts all props from `Button`
400
-
401
- ###### `<Combobox.Primitives.TriggerTag.Default/>`
368
+ - **`<Combobox.Primitives.TriggerIndicator>`** - Dropdown chevron icon
369
+ - **`<Combobox.Primitives.TriggerClear>`** - Clear button
370
+ - **`<Combobox.Primitives.TriggerText>`** - Selected value text
371
+ - **`<Combobox.Primitives.TriggerPlaceholder>`** - Placeholder text
372
+ - **`<Combobox.Primitives.TriggerTagsContainer>`** - Multi-select tags container
373
+ - **`<Combobox.Primitives.TriggerTag.*>`** - Tag components for multi-select
402
374
 
403
- A pre-composed tag with text and remove button.
375
+ For detailed primitive documentation, see the [Primitives](#primitives) section above.
404
376
 
405
- Props:
406
- | Name | Type | Default | Description |
407
- | ---- | ---- | ------- | ----------- |
408
- | value | string | required | The value this tag represents |
377
+ ## Type Examples
409
378
 
410
- Example of a custom tag layout:
379
+ ### Single Select Types
411
380
 
412
381
  ```tsx
413
- <Combobox.Primitives.TriggerTag.Root value="example">
414
- <Icon icon={CustomIcon} />
415
- <Combobox.Primitives.TriggerTag.Text>
416
- Custom Tag
417
- </Combobox.Primitives.TriggerTag.Text>
418
- <Combobox.Primitives.TriggerTag.Button
419
- icon={{ icon: XIcon, alt: "Remove" }}
420
- />
421
- </Combobox.Primitives.TriggerTag.Root>
422
- ```
423
-
424
- Example of using the default tag:
425
-
426
- ```tsx
427
- <Combobox.Primitives.TriggerTag.Default value="example" />
382
+ // String values (recommended)
383
+ const [value, setValue] = useState<string>("");
428
384
  ```
429
385
 
430
- Complete example using primitives for a custom trigger layout:
386
+ ### Multi Select Types
431
387
 
432
388
  ```tsx
433
- <Combobox.Root>
434
- <Combobox.Trigger>
435
- <Stack direction="row" justify="space-between" align="center" w="full">
436
- {/* Left side: Text or Tags */}
437
- <Box flex="1" overflow="hidden">
438
- <Combobox.Primitives.TriggerTagsContainer>
439
- <Combobox.Primitives.TriggerTag.Default value="tag1" />
440
- <Combobox.Primitives.TriggerTag.Default value="tag2" />
441
- </Combobox.Primitives.TriggerTagsContainer>
442
- </Box>
443
-
444
- {/* Right side: Clear and Indicator */}
445
- <Stack direction="row" gap="1" align="center">
446
- <Combobox.Primitives.TriggerClear />
447
- <Box borderLeft="1" h="4" />
448
- <Combobox.Primitives.TriggerIndicator />
449
- </Stack>
450
- </Stack>
451
- </Combobox.Trigger>
452
- <Combobox.Content>{/* ... */}</Combobox.Content>
453
- </Combobox.Root>
389
+ // String array values (recommended)
390
+ const [values, setValues] = useState<string[]>([]);
454
391
  ```
455
392
 
456
393
  ### Legacy Behavior (⚠️ Deprecated)
457
394
 
458
- > **Warning**: Legacy behavior is deprecated and will be removed in a future version. New implementations should use string values instead of objects.
459
-
460
- The `legacyBehavior` prop changes how values are handled:
461
-
462
- - When `false` (default, recommended): Values are simple strings
463
- - When `true` (deprecated): Values are objects with `{ value: string; label?: string }`
464
-
465
- #### Legacy Single Select Types
395
+ > **Warning**: Legacy behavior is deprecated and will be removed in a future version.
466
396
 
467
397
  ```tsx
468
398
  // ⚠️ Deprecated - Don't use in new code
469
- const [value, setValue] = useState<{ value: string; label?: string }>()
399
+ const [value, setValue] = useState<{ value: string; label?: string }>();
470
400
 
471
401
  <Combobox.Root
472
402
  value={value}
@@ -475,17 +405,15 @@ const [value, setValue] = useState<{ value: string; label?: string }>()
475
405
  >
476
406
  ```
477
407
 
478
- #### Legacy Multi Select Types
408
+ ## References
479
409
 
480
- ```tsx
481
- // ⚠️ Deprecated - Don't use in new code
482
- const [values, setValues] = useState<Array<{ value: string; label?: string }>>([])
410
+ - [Storybook Demo](https://storybook.telegraph.dev/?path=/docs/combobox)
411
+ - [ARIA Combobox Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/)
483
412
 
484
- <Combobox.Root
485
- value={values}
486
- onValueChange={setValues}
487
- legacyBehavior={true}
488
- >
489
- ```
413
+ ## Contributing
414
+
415
+ See our [Contributing Guide](../../CONTRIBUTING.md) for more details.
416
+
417
+ ## License
490
418
 
491
- This object-based value pattern is only maintained for backwards compatibility and should not be used in new code. It will be removed in a future major version.
419
+ MIT License - see [LICENSE](../../LICENSE) for details.