Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/www/src/components/datatable-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ export const columns: DataTableColumnDef<Payment, unknown>[] = [
],
filterType: 'multiselect',
enableColumnFilter: true,
enableHiding: true,

enableHiding: true
},
{
accessorKey: 'email',
header: 'Email',
cell: ({ row }) => <div className='lowercase'>{row.getValue('email')}</div>
cell: ({ row }) => <div className='lowercase'>{row.getValue('email')}</div>,
enableColumnFilter: true
},
{
accessorKey: 'amount',
Expand Down
49 changes: 49 additions & 0 deletions apps/www/src/components/playground/combobox-examples.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client';

import { Combobox, Flex } from '@raystack/apsara';
import PlaygroundLayout from './playground-layout';

export function ComboboxExamples() {
return (
<PlaygroundLayout title='Combobox'>
<Flex gap='large' wrap='wrap'>
<Combobox>
<Combobox.Input placeholder='Select a fruit' width={240} />
<Combobox.Content>
<Combobox.Item value='apple'>Apple</Combobox.Item>
<Combobox.Item value='banana'>Banana</Combobox.Item>
<Combobox.Item value='blueberry'>Blueberry</Combobox.Item>
<Combobox.Item value='grapes'>Grapes</Combobox.Item>
<Combobox.Item value='pineapple'>Pineapple</Combobox.Item>
</Combobox.Content>
</Combobox>
<Combobox multiple>
<Combobox.Input placeholder='Select fruits' width={300} />
<Combobox.Content>
<Combobox.Item value='apple'>Apple</Combobox.Item>
<Combobox.Item value='banana'>Banana</Combobox.Item>
<Combobox.Item value='blueberry'>Blueberry</Combobox.Item>
<Combobox.Item value='grapes'>Grapes</Combobox.Item>
<Combobox.Item value='pineapple'>Pineapple</Combobox.Item>
</Combobox.Content>
</Combobox>
<Combobox>
<Combobox.Input placeholder='Grouped items' width={240} />
<Combobox.Content>
<Combobox.Group>
<Combobox.Label>Fruits</Combobox.Label>
<Combobox.Item value='apple'>Apple</Combobox.Item>
<Combobox.Item value='banana'>Banana</Combobox.Item>
</Combobox.Group>
<Combobox.Separator />
<Combobox.Group>
<Combobox.Label>Vegetables</Combobox.Label>
<Combobox.Item value='carrot'>Carrot</Combobox.Item>
<Combobox.Item value='broccoli'>Broccoli</Combobox.Item>
</Combobox.Group>
</Combobox.Content>
</Combobox>
</Flex>
</PlaygroundLayout>
);
}
9 changes: 5 additions & 4 deletions apps/www/src/components/playground/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './amount-examples';
export * from './announcement-bar-examples';
export * from './avatar-examples';
export * from './badge-examples';
Expand All @@ -8,14 +9,15 @@ export * from './callout-examples';
export * from './checkbox-examples';
export * from './chip-examples';
export * from './code-block-examples';
export * from './combobox-examples';
export * from './command-examples';
export * from './container-examples';
export * from './data-table-examples';
export * from './dialog-examples';
export * from './dropdown-menu-examples';
export * from './empty-state-examples';
export * from './flex-examples';
export * from './filter-chip-examples';
export * from './flex-examples';
export * from './headline-examples';
export * from './icon-button-examples';
export * from './image-examples';
Expand All @@ -31,14 +33,13 @@ export * from './select-examples';
export * from './separator-examples';
export * from './sheet-examples';
export * from './sidebar-examples';
export * from './skeleton-examples';
export * from './slider-examples';
export * from './spinner-examples';
export * from './switch-examples';
export * from './table-examples';
export * from './tabs-examples';
export * from './text-examples';
export * from './text-area-examples';
export * from './text-examples';
export * from './toast-examples';
export * from './tooltip-examples';
export * from './skeleton-examples';
export * from './amount-examples';
90 changes: 47 additions & 43 deletions apps/www/src/content/docs/components/combobox/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const getCode = (props: Record<string, unknown>) => {
const { multiple, ...rest } = props;
return `
<Combobox${getPropsString({ ...(multiple ? { multiple } : {}) })}>
<Combobox.Input placeholder="Enter a fruit"${getPropsString(rest)} />
<Combobox.Input placeholder="Select a fruit"${getPropsString(rest)} width={240} />
<Combobox.Content>
<Combobox.Item>Apple</Combobox.Item>
<Combobox.Item>Banana</Combobox.Item>
Expand Down Expand Up @@ -48,53 +48,24 @@ export const basicDemo = {
</Combobox>`
};

export const iconDemo = {
type: 'code',
code: `
<Combobox>
<Combobox.Input placeholder="Enter a fruit" />
<Combobox.Content>
<Combobox.Item leadingIcon={<Info size={16} />}>Apple</Combobox.Item>
<Combobox.Item leadingIcon={<X size={16} />}>Banana</Combobox.Item>
<Combobox.Item leadingIcon={<Home size={16} />}>Grape</Combobox.Item>
<Combobox.Item leadingIcon={<Laugh size={16} />}>Orange</Combobox.Item>
</Combobox.Content>
</Combobox>`
};

export const sizeDemo = {
type: 'code',
code: `
<Flex align="center" gap="large">
<Combobox>
<Combobox.Input size="small" placeholder="Small combobox" />
<Combobox.Content>
<Combobox.Item>Option 1</Combobox.Item>
<Combobox.Item>Option 2</Combobox.Item>
</Combobox.Content>
</Combobox>
<Combobox>
<Combobox.Input placeholder="Large combobox" />
<Combobox.Content>
<Combobox.Item>Option 1</Combobox.Item>
<Combobox.Item>Option 2</Combobox.Item>
</Combobox.Content>
</Combobox>
</Flex>`
};

export const multipleDemo = {
type: 'code',
code: `
<Combobox multiple>
<Combobox.Input placeholder="Select fruits..." />
<Combobox.Input placeholder="Select fruits" width={300} />
<Combobox.Content>
<Combobox.Item>Apple</Combobox.Item>
<Combobox.Item>Banana</Combobox.Item>
<Combobox.Item>Grape</Combobox.Item>
<Combobox.Item>Orange</Combobox.Item>
<Combobox.Item>Pineapple</Combobox.Item>
<Combobox.Item>Mango</Combobox.Item>
<Combobox.Item>Pineapple</Combobox.Item>
<Combobox.Item>Strawberry</Combobox.Item>
<Combobox.Item>Watermelon</Combobox.Item>
<Combobox.Item>Kiwi</Combobox.Item>
<Combobox.Item>Lemon</Combobox.Item>
<Combobox.Item>Lime</Combobox.Item>
<Combobox.Item>Lemon</Combobox.Item>
Comment on lines 54 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove the duplicate “Lemon” option in the multiple selection demo.
It’s likely an accidental duplicate and can confuse the example.

✂️ Proposed fix
       <Combobox.Item>Kiwi</Combobox.Item>
       <Combobox.Item>Lemon</Combobox.Item>
       <Combobox.Item>Lime</Combobox.Item>
-      <Combobox.Item>Lemon</Combobox.Item>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Combobox multiple>
<Combobox.Input placeholder="Select fruits..." />
<Combobox.Input placeholder="Select fruits" width={300} />
<Combobox.Content>
<Combobox.Item>Apple</Combobox.Item>
<Combobox.Item>Banana</Combobox.Item>
<Combobox.Item>Grape</Combobox.Item>
<Combobox.Item>Orange</Combobox.Item>
<Combobox.Item>Pineapple</Combobox.Item>
<Combobox.Item>Mango</Combobox.Item>
<Combobox.Item>Pineapple</Combobox.Item>
<Combobox.Item>Strawberry</Combobox.Item>
<Combobox.Item>Watermelon</Combobox.Item>
<Combobox.Item>Kiwi</Combobox.Item>
<Combobox.Item>Lemon</Combobox.Item>
<Combobox.Item>Lime</Combobox.Item>
<Combobox.Item>Lemon</Combobox.Item>
<Combobox multiple>
<Combobox.Input placeholder="Select fruits" width={300} />
<Combobox.Content>
<Combobox.Item>Apple</Combobox.Item>
<Combobox.Item>Banana</Combobox.Item>
<Combobox.Item>Grape</Combobox.Item>
<Combobox.Item>Orange</Combobox.Item>
<Combobox.Item>Mango</Combobox.Item>
<Combobox.Item>Pineapple</Combobox.Item>
<Combobox.Item>Strawberry</Combobox.Item>
<Combobox.Item>Watermelon</Combobox.Item>
<Combobox.Item>Kiwi</Combobox.Item>
<Combobox.Item>Lemon</Combobox.Item>
<Combobox.Item>Lime</Combobox.Item>
</Combobox.Content>
</Combobox>
🤖 Prompt for AI Agents
In `@apps/www/src/content/docs/components/combobox/demo.ts` around lines 54 - 68,
The demo includes a duplicated option label "Lemon" in the multiple-selection
Combobox example; edit the demo in
apps/www/src/content/docs/components/combobox/demo.ts and remove the extra
Combobox.Item that renders "Lemon" so there is only one <Combobox.Item> with the
label "Lemon" in the <Combobox.Content> list (leave the other Combobox.Item
entries unchanged).

</Combobox.Content>
</Combobox>`
};
Expand All @@ -103,23 +74,56 @@ export const groupDemo = {
type: 'code',
code: `
<Combobox>
<Combobox.Input placeholder="Enter a fruit" />
<Combobox.Input placeholder="Search items" width={240} />
<Combobox.Content>
<Combobox.Group>
<Combobox.Label>Fruits</Combobox.Label>
<Combobox.Item>Apple</Combobox.Item>
<Combobox.Item>Banana</Combobox.Item>
<Combobox.Item value="apple">Apple</Combobox.Item>
<Combobox.Item value="banana">Banana</Combobox.Item>
</Combobox.Group>
<Combobox.Separator />
<Combobox.Group>
<Combobox.Label>Vegetables</Combobox.Label>
<Combobox.Item>Carrot</Combobox.Item>
<Combobox.Item>Broccoli</Combobox.Item>
<Combobox.Item value="carrot">Carrot</Combobox.Item>
<Combobox.Item value="broccoli">Broccoli</Combobox.Item>
</Combobox.Group>
</Combobox.Content>
</Combobox>`
};

export const iconDemo = {
type: 'code',
code: `
<Combobox>
<Combobox.Input placeholder="Select a fruit" width={240} />
<Combobox.Content>
<Combobox.Item value="apple" leadingIcon={<Info size={16} />}>Apple</Combobox.Item>
<Combobox.Item value="banana" leadingIcon={<X size={16} />}>Banana</Combobox.Item>
<Combobox.Item value="grape" leadingIcon={<Home size={16} />}>Grape</Combobox.Item>
<Combobox.Item value="orange" leadingIcon={<Laugh size={16} />}>Orange</Combobox.Item>
</Combobox.Content>
</Combobox>`
};

export const withLabelDemo = {
type: 'code',
code: `
<Combobox>
<Combobox.Input
placeholder="Select a fruit"
label="Favorite Fruit"
helperText="Choose your favorite fruit"
width={240}
/>
<Combobox.Content>
<Combobox.Item value="apple">Apple</Combobox.Item>
<Combobox.Item value="banana">Banana</Combobox.Item>
<Combobox.Item value="blueberry">Blueberry</Combobox.Item>
<Combobox.Item value="grapes">Grapes</Combobox.Item>
</Combobox.Content>
</Combobox>`
};

export const controlledDemo = {
type: 'code',
code: `
Expand Down
52 changes: 23 additions & 29 deletions apps/www/src/content/docs/components/combobox/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ tag: new
import {
playground,
basicDemo,
sizeDemo,
iconDemo,
multipleDemo,
groupDemo,
controlledDemo
iconDemo,
withLabelDemo,
controlledDemo,
} from "./demo.ts";

<Demo data={playground} />
Expand All @@ -26,7 +26,7 @@ import { Combobox } from "@raystack/apsara";

The Combobox component is composed of several parts, each with their own props.

The root element is the parent component that manages the combobox state including open/close, input value, and selection. It is built using [Ariakit ComboboxProvider](https://ariakit.org/reference/combobox-provider) and [Radix Popover](https://www.radix-ui.com/primitives/docs/components/popover).
The root element is the parent component that manages the combobox state including open/close, input value, and selection.

<auto-type-table path="./props.ts" name="ComboboxRootProps" />

Expand All @@ -44,7 +44,9 @@ The dropdown container that holds the combobox items.

### Combobox.Item Props

Individual selectable options within the combobox.
Individual selectable options within the combobox. In single mode, selecting an item closes the dropdown. In multiple mode, items show checkboxes and the dropdown remains open.

When no `value` prop is provided, the text content of `children` is used as the value.

<auto-type-table path="./props.ts" name="ComboboxItemProps" />

Expand All @@ -56,7 +58,7 @@ A way to group related combobox items together.

### Combobox.Label Props

Renders a label in a combobox group. This component should be used inside Combobox.Group.
Renders a label in a combobox group. This component should be wrapped with `Combobox.Group`.

<auto-type-table path="./props.ts" name="ComboboxLabelProps" />

Expand All @@ -68,46 +70,38 @@ Visual divider between combobox items or groups.

## Examples

### Basic Combobox
### Basic

A simple combobox with search functionality.
A simple combobox with search filtering built in. Type to filter options.

<Demo data={basicDemo} />

### Size
### With Icons

The combobox input supports different sizes.
You can pass the `leadingIcon` prop to `Combobox.Item` to display icons before item text.

<Demo data={sizeDemo} />
<Demo data={iconDemo} />

### Multiple Selection
### With Label and Helper Text

To enable multiple selection, pass the `multiple` prop to the Combobox root element.
The input supports `label`, `helperText`, and other `InputField` props.

When multiple selection is enabled, the value, onValueChange, and defaultValue will be an array of strings. Selected items are displayed as chips in the input field.

<Demo data={multipleDemo} />
<Demo data={withLabelDemo} />

### Groups and Separators

Use Combobox.Group, Combobox.Label, and Combobox.Separator to organize items into logical groups.
Organize items into groups with labels and visual separators. Groups and labels are automatically hidden when the user is searching.

<Demo data={groupDemo} />

### Controlled

You can control the combobox value and input value using the `value`, `onValueChange`, `inputValue`, and `onInputValueChange` props.
### Multiple Selection

<Demo data={controlledDemo} />
Pass the `multiple` prop to enable multi-select. Selected values appear as chips in the input. Items display checkboxes in multiple mode.

## Accessibility
<Demo data={multipleDemo} />

The Combobox component follows WAI-ARIA guidelines:
### Controlled

- Input has role `combobox`
- Content has role `listbox`
- Items have role `option`
- Supports keyboard navigation (Arrow keys, Enter, Escape)
- ARIA labels and descriptions for screen readers
- Focus management between input and listbox
Use `value` and `onValueChange` for controlled behavior.

<Demo data={controlledDemo} />
Loading