Skip to main content
Glama
multiselect.stories.tsx5.3 kB
import type { Meta, StoryObj } from '@storybook/react'; import { expect, within } from '@storybook/test'; import { useState } from 'react'; import { MultiSelect } from '.'; /** * MultiSelect Component Stories * * The MultiSelect component provides a comprehensive multi-selection interface with search functionality, * keyboard navigation, and visual feedback through badges. Built on Command component primitives, * it offers an intuitive way to handle complex selection scenarios. * * ## Key Features * - **Multi-Selection**: Select multiple values with instant visual feedback * - **Search & Filter**: Real-time filtering of options as you type * - **Keyboard Navigation**: Full arrow key navigation with optional looping * - **Badge Display**: Selected items shown as removable badges * - **Accessibility**: Screen reader support and comprehensive ARIA attributes * - **Flexible State**: Both controlled and uncontrolled usage patterns * * ## When to Use * - Tag/category selection in content management * - Multi-user assignment in project management * - Permission/feature selection in settings * - Filter selection in search and data interfaces * - Skills/interests selection in profiles * - Any scenario requiring multiple choice selection */ const meta: Meta<typeof MultiSelect> = { title: 'Components/MultiSelect', component: MultiSelect, parameters: { docs: { description: { component: ` A powerful multi-selection component with search and filtering capabilities. ### Accessibility Features: - **Keyboard Navigation**: Arrow keys for navigation, Enter to select/deselect - **Search Integration**: Real-time filtering with screen reader announcements - **Badge Management**: Backspace and Delete keys for removing selections - **Focus Management**: Clear focus indicators and logical tab flow - **ARIA Support**: Proper roles, labels, and state announcements ### Interaction Patterns: - **Type to Search**: Filter options by typing in the input field - **Click to Select**: Click options to add/remove from selection - **Badge Removal**: Click X on badges or use keyboard shortcuts - **Keyboard Navigation**: Arrow keys move through options, Enter selects ### State Management: - **Controlled**: Use \`values\` and \`onValueChange\` props for external state - **Uncontrolled**: Use \`defaultValues\` for internal state management - **Real-time Updates**: Selection changes immediately update the UI ### Use Cases: - Multi-user assignment interfaces - Tag and category selection - Permission and feature toggles - Advanced filtering systems `, }, }, a11y: { config: { rules: [ { id: 'color-contrast', enabled: true, }, { id: 'keyboard-navigation', enabled: true, }, ], }, }, }, tags: ['autodocs'], argTypes: { values: { description: 'Array of selected values (controlled mode)', control: false, }, defaultValues: { description: 'Default selected values (uncontrolled mode)', control: { type: 'object' }, }, onValueChange: { description: 'Callback fired when selection changes', action: 'values changed', }, loop: { description: 'Whether keyboard navigation loops through options', control: 'boolean', }, }, } satisfies Meta<typeof MultiSelect>; export default meta; type Story = StoryObj<typeof MultiSelect>; /** * ## Basic Examples * * These stories demonstrate the core functionality and common usage patterns of MultiSelect. */ /** * ### Default Behavior * * Basic multi-select with framework options. Shows the standard usage pattern * with search functionality and badge display. */ export const Default: Story = { render: () => { const [values, setValues] = useState<string[]>(['react']); const handleValueChange = (newValues: string[] | string): void => { setValues(Array.isArray(newValues) ? newValues : [newValues]); }; return ( <div className="w-80"> <MultiSelect values={values} onValueChange={handleValueChange}> <MultiSelect.Trigger> <MultiSelect.Input placeholder="Select frameworks..." /> </MultiSelect.Trigger> <MultiSelect.Content> <MultiSelect.List> <MultiSelect.Item value="react">⚛️ React</MultiSelect.Item> <MultiSelect.Item value="vue">💚 Vue.js</MultiSelect.Item> <MultiSelect.Item value="svelte">🧡 Svelte</MultiSelect.Item> <MultiSelect.Item value="angular">🔴 Angular</MultiSelect.Item> <MultiSelect.Item value="solid">🔷 SolidJS</MultiSelect.Item> </MultiSelect.List> </MultiSelect.Content> </MultiSelect> <div className="mt-4 text-gray-600 text-sm"> Selected: <strong>{values.length}</strong> framework {values.length !== 1 ? 's' : ''} </div> </div> ); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); const input = canvas.getByRole('combobox'); await expect(input).toBeInTheDocument(); await expect(input).toHaveAttribute('placeholder', 'Select frameworks...'); }, };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server