Skip to content

Commit a91b762

Browse files
committed
[combobox] Fix mapped item values
1 parent efe70d4 commit a91b762

15 files changed

Lines changed: 436 additions & 177 deletions

File tree

docs/src/app/(docs)/react/components/combobox/page.mdx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,17 @@ import { Combobox } from '@base-ui/react/combobox';
7575

7676
Choose whether selection uses full item objects or primitive keys.
7777

78-
To select full objects, omit `itemToValue`. The `value`, `defaultValue`, and selection callbacks then use the same object type as `items`.
78+
The `value`, `defaultValue`, and selection callbacks use the same object type as `items` by default.
7979

80-
To select a primitive field such as an ID, `itemToValue` is required:
80+
To select a primitive field, such as an ID, `itemToValue` is required:
8181

82-
```tsx
82+
```tsx title="Primitive values"
8383
<Combobox.Root items={countries} itemToValue={(country) => country.code} />
8484
```
8585

8686
Render functions still receive full objects, while selection state and callbacks use the primitive key. When rendering items from `<Combobox.List>` or `<Combobox.Collection>`, omit `<Combobox.Item value>`. For manually rendered virtualized items, provide `index`.
8787

88-
Labels are inferred automatically for primitive keys. If `itemToValue` returns an object, provide `itemToStringLabel` to display its label in the input.
88+
When `itemToValue` returns a primitive, a source item's text or numeric `label` is used automatically. Otherwise, provide `itemToStringLabel`, which receives the mapped value. If `itemToValue` returns an object, also keep its references stable or provide `isItemEqualToValue` when equivalent objects may be recreated.
8989

9090
## Examples
9191

@@ -97,8 +97,8 @@ The following example shows a typed wrapper around the Combobox component with c
9797
import * as React from 'react';
9898
import { Combobox } from '@base-ui/react/combobox';
9999

100-
export function MyCombobox<Value, Multiple extends boolean | undefined = false>(
101-
props: Combobox.Root.Props<Value, Multiple>,
100+
export function MyCombobox<Value, Multiple extends boolean | undefined = false, Item = Value>(
101+
props: Combobox.Root.Props<Value, Multiple, Item>,
102102
): React.JSX.Element {
103103
return <Combobox.Root {...props}>{/* ... */}</Combobox.Root>;
104104
}

docs/src/app/(docs)/react/components/combobox/types.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Doesn't render its own HTML element.
3535
| isItemEqualToValue | `((itemValue: Value, value: Value) => boolean)` | - | Custom comparison logic used to determine if a combobox item value matches the current selected value. Useful when item values are objects without matching referentially.&#xA;Defaults to `Object.is` comparison. |
3636
| itemToStringLabel | `((itemValue: Value) => string)` | - | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for display in the input.&#xA;If the shape of the object is `{ value, label }`, the label will be used automatically without needing to specify this prop. |
3737
| itemToStringValue | `((itemValue: Value) => string)` | - | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for form submission.&#xA;If the shape of the object is `{ value, label }`, the value will be used automatically without needing to specify this prop. |
38-
| itemToValue | `((item: Item) => Value)` | - | Maps an entry from the `items` array to the value emitted for its item. Use it to select a&#xA;projection of the source item (for example `item.value`) while keeping filtering, grouping,&#xA;and rendering on the source item. When omitted, the source item is the value. |
38+
| itemToValue | `((item: Item) => Value)` | - | Maps an entry from the `items` array to the value emitted for its item. Use it to select a&#xA;field from the source item (for example `item.value`) while keeping filtering, grouping,&#xA;and rendering on the source item. When omitted, the source item is the value.&#xA;The returned value must not be `undefined`. Use `null` for an empty item value. |
3939
| items | `Item[] \| Group<Item>[]` | - | The items to be displayed in the list.&#xA;Can be either a flat array of items or an array of groups with items. |
4040
| limit | `number` | `-1` | The maximum number of items to display in the list. |
4141
| locale | `Intl.LocalesArgument` | - | The locale to use for string comparison.&#xA;Defaults to the user's runtime locale. |
@@ -643,17 +643,17 @@ Renders a `<div>` element.
643643

644644
**Item Props:**
645645

646-
| Prop | Type | Default | Description |
647-
| :----------- | :------------------------------------------------------------------------------------------ | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
648-
| value | `any` | `null` | A unique value that identifies this item. |
649-
| onClick | `((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)` | - | An optional click handler for the item when selected.&#xA;It fires when clicking the item with the pointer, as well as when pressing `Enter` with the keyboard if the item is highlighted when the `Input` or `List` element has focus. |
650-
| index | `number` | - | The index of the item in the list. Improves performance when specified by avoiding the need to calculate the index automatically from the DOM. |
651-
| nativeButton | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it&#xA;via the `render` prop.&#xA;Set to `true` if the rendered element is a native button. |
652-
| disabled | `boolean` | `false` | Whether the component should ignore user interaction. |
653-
| children | `React.ReactNode` | - | - |
654-
| className | `string \| ((state: Combobox.Item.State) => string \| undefined)` | - | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state. |
655-
| style | `React.CSSProperties \| ((state: Combobox.Item.State) => React.CSSProperties \| undefined)` | - | Style applied to the element, or a function that&#xA;returns a style object based on the component's state. |
656-
| render | `ReactElement \| ((props: HTMLProps, state: Combobox.Item.State) => ReactElement)` | - | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
646+
| Prop | Type | Default | Description |
647+
| :----------- | :------------------------------------------------------------------------------------------ | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
648+
| value | `any` | `null` | A unique value that identifies this item.&#xA;When the root derives a value with `itemToValue`, that derived value takes precedence. Omit&#xA;this prop for items rendered from a collection, or pass the mapped value. |
649+
| onClick | `((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)` | - | An optional click handler for the item when selected.&#xA;It fires when clicking the item with the pointer, as well as when pressing `Enter` with the keyboard if the item is highlighted when the `Input` or `List` element has focus. |
650+
| index | `number` | - | The index of the item in the list. Required to derive the mapped value for manually&#xA;rendered virtualized items when `itemToValue` is set. Otherwise, providing it improves&#xA;performance by avoiding the need to calculate the index automatically from the DOM. |
651+
| nativeButton | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it&#xA;via the `render` prop.&#xA;Set to `true` if the rendered element is a native button. |
652+
| disabled | `boolean` | `false` | Whether the component should ignore user interaction. |
653+
| children | `React.ReactNode` | - | - |
654+
| className | `string \| ((state: Combobox.Item.State) => string \| undefined)` | - | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state. |
655+
| style | `React.CSSProperties \| ((state: Combobox.Item.State) => React.CSSProperties \| undefined)` | - | Style applied to the element, or a function that&#xA;returns a style object based on the component's state. |
656+
| render | `ReactElement \| ((props: HTMLProps, state: Combobox.Item.State) => ReactElement)` | - | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
657657

658658
**Item Data Attributes:**
659659

docs/src/app/(docs)/react/components/page.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ An input combined with a list of predefined items to select.
418418
- Sections:
419419
- Usage guidelines
420420
- Anatomy
421-
- TypeScript
421+
- Item values
422422
- Examples
423423
- Typed wrapper component
424424
- Multiple select

0 commit comments

Comments
 (0)