shadcn-multi-select-component

repository·main·Indexed 25 days ago

https://github.com/sersavan/shadcn-multi-select-component

A customizable, accessible multi-select component for React, built with shadcn/ui, Tailwind CSS, and Radix UI. It supports grouped options, responsive design, advanced animations via animationConfig, and programmatic control through MultiSelectRef. Optimized for complex use cases like analytics dashboards, it includes full ARIA support, keyboard navigation, and integration with React Hook Form.

Tokens
9.4K
Snippets
23
Records
39
Agent score
78%

What's inside multi-select-component

  1. Configure Responsive Design and Width Constraints

    main

    The component features automatic responsive behavior. When responsive={true} is enabled, the UI adapts based on screen width:

    • Mobile (< 640px): 2 badges max, compact mode.
    • Tablet (640px - 1024px): 4 badges max, normal mode.
    • Desktop (> 1024px): 6 badges max, full features.

    You can also enforce specific width constraints using minWidth and maxWidth props.

    <MultiSelect
    	options={options}
    	onValueChange={setSelected}
    	responsive={true}
    	minWidth="200px"
    	maxWidth="400px"
    	placeholder="Constrained width"
    />
  2. Accessibility features in MultiSelect

    main

    The MultiSelect component includes built-in accessibility support:

    ARIA Support

    • ARIA Live Regions: Automatic announcements for screen readers when selections change.
    • Role Attributes: Uses combobox, listbox, and option roles.
    • ARIA Labels & States: Includes descriptive labels and manages aria-expanded, aria-selected, and aria-disabled states.

    Keyboard Navigation

    • Tab: Focus component and navigate elements.
    • Enter/Space: Open dropdown and select options.
    • Arrow Keys: Navigate through options.
    • Escape: Close dropdown.
    • Backspace: Remove last selected item when search is empty.

    Screen Reader Announcements

    Automatically announces the number of options selected, dropdown state changes, search results count, and individual selection/deselection events.

  3. Use MultiSelect with grouped options

    main

    The component supports a complex, grouped data structure. Each group can have a heading and a list of options. Options can include custom icons and specific styles (like badgeColor, iconColor, or gradient) to enhance visual distinction.

    const complexStructure = [
    	{
    		heading: "Frontend Frameworks",
    		options: [
    			{
    				value: "react",
    				label: "React",
    				icon: ReactIcon,
    				style: { badgeColor: "#61DAFB", iconColor: "#282C34" },
    			},
    			{
    				value: "vue",
    				label: "Vue.js",
    				icon: VueIcon,
    				style: {
    					gradient: "linear-gradient(135deg, #4FC08D 0%, #42B883 100%)",
    				},
    			},
    			{
    				value: "angular",
    				label: "Angular",
    				icon: AngularIcon,
    				disabled: true,
    				style: { badgeColor: "#DD0031", iconColor: "#ffffff" },
    			},
    		],
    	},
    	{
    		heading: "State Management",
    		options: [
    			{ value: "redux", label: "Redux" },
    			{ value: "zustand", label: "Zustand" },
    			{ value: "recoil", label: "Recoil", disabled: true },
    		],
    	},
    ];
  4. Control MultiSelect Imperatively via Ref

    main

    You can access imperative methods by attaching a ref to the component. This allows you to reset, clear, focus, or manually set values.

    Available methods on the ref:

    • reset(): Resets to default values.
    • clear(): Clears all selections.
    • focus(): Focuses the component.
    • getSelectedValues(): Returns the current selected values.
    • setSelectedValues(values: string[]): Sets specific values.
    const multiSelectRef = useRef<MultiSelectRef>(null);
    
    // Reset to default values
    multiSelectRef.current?.reset();
    
    // Clear all selections
    multiSelectRef.current?.clear();
    
    // Focus the component
    multiSelectRef.current?.focus();
    
    // Get current values
    const values = multiSelectRef.current?.getSelectedValues();
    
    // Set specific values
    multiSelectRef.current?.setSelectedValues(["react", "vue"]);
  5. Install the MultiSelect Component

    main

    Follow these steps to integrate the MultiSelect component into your React project:

    1. Copy the Component: Copy src/components/multi-select.tsx from the repository to your project's components directory.
    2. Install Dependencies: Install the required peer dependencies using npm:
      npm install react react-dom
      npm install @radix-ui/react-popover @radix-ui/react-separator
      npm install lucide-react class-variance-authority clsx tailwind-merge cmdk
    3. Setup shadcn/ui Components: Ensure you have the following shadcn/ui components installed in your project:
      npx shadcn@latest add button badge popover command separator
    4. Configure Path Aliases: Ensure your project is configured to resolve the @/ alias (e.g., in tsconfig.json for Next.js or vite.config.ts for Vite).
    5. Setup Utility Function: Ensure you have a cn utility function available in src/lib/utils.ts to handle Tailwind class merging.
    cp src/components/multi-select.tsx your-project/components/
    
    # Install Dependencies
    npm install react react-dom
    npm install @radix-ui/react-popover @radix-ui/react-separator
    npm install lucide-react class-variance-authority clsx tailwind-merge cmdk
    
    # Setup shadcn/ui Components
    npx shadcn@latest add button badge popover command separator
  6. Customize MultiSelect appearance and variants

    main

    Style Customization

    Pass custom Tailwind CSS classes via the className prop to override default styles.

    Custom Variants

    You can extend the component's visual styles by adding new variants to the multiSelectVariants (which uses cva).

    Theme Integration

    The component automatically adapts to light and dark modes when used with a shadcn/ui theme provider.

    // Style Customization
    <MultiSelect
    	className="my-custom-class"
    	options={options}
    	onValueChange={setSelected}
    />
    
    // Custom Variants (extending multiSelectVariants)
    const customVariants = cva("base-classes", {
    	variants: {
    		variant: {
    			premium: "bg-gradient-to-r from-purple-500 to-pink-500 text-white",
    			minimal: "bg-transparent border-dashed",
    		},
    	},
    });
  7. Configure Path Aliases for MultiSelect

    main

    The component relies on @/ path aliases. Configure them based on your environment:

    Next.js

    Update tsconfig.json or jsconfig.json:

    {
    	"compilerOptions": {
    		"baseUrl": ".",
    		"paths": {
    			"@/*": ["./src/*"]
    		}
    	}
    }

    Vite

    Update vite.config.ts:

    import { defineConfig } from "vite";
    import path from "path";
    
    export default defineConfig({
    	resolve: {
    		alias: {
    			"@": path.resolve(__dirname, "./src"),
    		},
    	},
    });
  8. Customize Badge animations and styles

    main

    The MultiSelect component supports highly customizable badges for selected items. You can control the animation and visual style through the MultiSelectOption object or the animationConfig prop.

    Option-level Styling

    Each option can provide a style object:

    • badgeColor: Sets a specific background color for the badge.
    • gradient: Sets a CSS gradient background (automatically sets text color to white).
    • iconColor: Sets a specific color for the option's icon.

    Animation Configuration

    You can pass an animationConfig to the component to globally control the timing of badge animations:

    • duration: The time in seconds for the animation.
    • delay: The delay in seconds before the animation starts.
  9. Troubleshoot MultiSelect Issues

    main

    Animation Issues

    If animations are not working, ensure you are using the animationConfig object instead of passing animation props directly.

    • Correct: animationConfig={{ badgeAnimation: "pulse" }}
    • Incorrect: badgeAnimation="pulse"

    Form Validation

    • Ensure onValueChange is correctly connected to the form field.
    • Use proper default values to avoid controlled/uncontrolled component warnings.
    • Ensure your validation schema (e.g., Zod) handles empty arrays appropriately.

    Performance

    • For large lists, consider implementing virtualization.
    • Use React.memo for option components.
    • Debounce search functionality if performance lags.
  10. Integrate MultiSelect with Dashboards and Charts

    main

    MultiSelect is designed for real-time data filtering in analytics dashboards. You can use the onValueChange callback to filter data arrays that are then passed to charting libraries like Recharts.

    import { MultiSelect } from "@/components/multi-select";
    import { BarChart, Bar, XAxis, YAxis, ResponsiveContainer } from "recharts";
    
    const Dashboard = () => {
    	const [selectedCategories, setSelectedCategories] = useState(["2024"]);
    
    	const filteredData = data.filter((item) =>
    		selectedCategories.includes(item.category)
    	);
    
    	return (
    		<div className="space-y-4">
    			<MultiSelect
    				options={[
    					{ value: "2024", label: "2024", icon: CalendarIcon },
    					{ value: "2023", label: "2023", icon: CalendarIcon },
    				]}
    				onValueChange={setSelectedCategories}
    				defaultValue={selectedCategories}
    				placeholder="Select time period"
    				responsive={true}
    			/>
    
    			<ResponsiveContainer width="100%" height={300}>
    				<BarChart data={filteredData}>
    					<XAxis dataKey="name" />
    					<YAxis />
    					<Bar dataKey="value" fill="#8884d8" />
    				</BarChart>
    			</ResponsiveContainer>
    		</div>
    	);
    };
  11. Use Grouped Options in MultiSelect

    main

    You can organize options into logical groups by providing an array of objects containing a heading and an array of options.

    const groupedOptions = [
    	{
    		heading: "Frontend Frameworks",
    		options: [
    			{ value: "react", label: "React" },
    			{ value: "vue", label: "Vue.js" },
    			{ value: "angular", label: "Angular", disabled: true },
    		],
    	},
    	{
    		heading: "Backend Technologies",
    		options: [
    			{ value: "node", label: "Node.js" },
    			{ value: "python", label: "Python" },
    		],
    	},
    ];
    
    <MultiSelect
    	options={groupedOptions}
    	onValueChange={setSelected}
    	placeholder="Select from groups..."
    />;
  12. Customize MultiSelect option styling

    main

    You can apply custom colors or gradients to individual options using the style property within a MultiSelectOption object.

    // Single color badge with custom icon color
    {
      value: "react",
      label: "React",
      style: {
        badgeColor: "#61DAFB",
        iconColor: "#282C34"
      }
    }
    
    // Gradient badge (icon will be white by default)
    {
      value: "vue",
      label: "Vue.js",
      style: {
        gradient: "linear-gradient(135deg, #4FC08D 0%, #42B883 100%)"
      }
    }