Select

A select allows a user to choose one option from a list of options.

Usage

'use client'

import { BsSelect } from '@workspace/ui/components/Select'
import React from 'react'

const languages = [
    { id: 1, name: 'English' },
    { id: 2, name: 'Spanish' },
    { id: 3, name: 'French' },
    { id: 4, name: 'German' },
    { id: 5, name: 'Italian' },
]

export function SelectDemo() {
    return (
        <div className="space-y-4 w-full">
            <BsSelect options={languages} selectionMode="single" />
        </div>
    )
}

Single Select Examples

Basic

'use client'

import { BsSelect } from '@workspace/ui/components/Select'
import React from 'react'

const languages = [
    { id: 1, name: 'English' },
    { id: 2, name: 'Spanish' },
    { id: 3, name: 'French' },
    { id: 4, name: 'German' },
    { id: 5, name: 'Italian' },
]

export function SelectDemo() {
    return (
        <div className="space-y-4 w-full">
            <BsSelect options={languages} selectionMode="single" />
        </div>
    )
}

Disabled

import { BsSelect } from '@workspace/ui/components/Select'

export function SelectDisabled() {
    return <BsSelect isDisabled options={[]} />
}

Searchable

import { BsSelect } from '@workspace/ui/components/Select'

const languages = [
    { id: 1, name: 'English' },
    { id: 2, name: 'Spanish' },
    { id: 3, name: 'French' },
    { id: 4, name: 'German' },
    { id: 5, name: 'Italian' },
]

export function SelectSearchable() {
    return <BsSelect isSearchable options={languages} />
}

Customization

'use client'

import { Avatar, AvatarFallback } from '@workspace/ui/components/Avatar'
import { BsSelect } from '@workspace/ui/components/Select'

const users = [
    {
        id: 1,
        name: 'John Doe',
        email: 'john@example.com',
        className: 'bg-sky-500',
    },
    {
        id: 2,
        name: 'Jane Smith',
        email: 'jane@example.com',
        className: 'bg-red-500',
    },
    {
        id: 3,
        name: 'Bob Johnson',
        email: 'bob@example.com',
        className: 'bg-green-500',
    },
]

export function SelectCustom() {
    return (
        <BsSelect
            options={users}
            defaultValue={1}
            renderValue={value => (
                <div className="flex items-center gap-2">
                    <Avatar className="size-5 text-xs">
                        <AvatarFallback className={value.className}>{value.name.charAt(0)}</AvatarFallback>
                    </Avatar>
                    <div className="flex flex-col">{value.name}</div>
                </div>
            )}
            renderOption={value => (
                <div className="flex items-center gap-2">
                    <Avatar>
                        <AvatarFallback className={value.className}>{value.name.charAt(0)}</AvatarFallback>
                    </Avatar>
                    <div className="flex flex-col">
                        <span>{value.name}</span>
                        <span className="opacity-60 text-xs">{value.email}</span>
                    </div>
                </div>
            )}
        />
    )
}

Multiple Select Examples

Basic

'use client'

import { BsSelect } from '@workspace/ui/components/Select'

const languages = [
    { id: 1, name: 'English' },
    { id: 2, name: 'Spanish' },
    { id: 3, name: 'French' },
    { id: 4, name: 'German' },
    { id: 5, name: 'Italian' },
]

export function SelectMultiple() {
    return <BsSelect selectionMode="multiple" options={languages} />
}

Disabled

'use client'

import { BsSelect } from '@workspace/ui/components/Select'

const languages = [
    { id: 1, name: 'English' },
    { id: 2, name: 'Spanish' },
    { id: 3, name: 'French' },
    { id: 4, name: 'German' },
    { id: 5, name: 'Italian' },
]

export function SelectMultipleDisabled() {
    return <BsSelect selectionMode="multiple" options={languages} isDisabled />
}

Searchable

import { BsSelect } from '@workspace/ui/components/Select'

const languages = [
    { id: 1, name: 'English' },
    { id: 2, name: 'Spanish' },
    { id: 3, name: 'French' },
    { id: 4, name: 'German' },
    { id: 5, name: 'Italian' },
]

export function SelectMultipleSearchable() {
    return <BsSelect selectionMode="multiple" options={languages} isSearchable />
}

Customization

'use client'

import { BsSelect } from '@workspace/ui/components/Select'

const languages = [
    {
        id: 1,
        name: 'English',
        flag: '🇬🇧',
    },
    {
        id: 2,
        name: 'Spanish',
        flag: '🇪🇸',
    },
    {
        id: 3,
        name: 'French',
        flag: '🇫🇷',
    },
]

export function SelectMultipleCustomization() {
    return (
        <BsSelect
            selectionMode="multiple"
            options={languages}
            renderValue={value => (
                <div className="flex items-center gap-2">
                    <span>{value.flag}</span>
                    <span>{value.name}</span>
                </div>
            )}
            renderOption={value => (
                <div className="flex items-center gap-2">
                    <span className="text-xl">{value.flag}</span>
                    <span>{value.name}</span>
                </div>
            )}
        />
    )
}

With Clear Button

import { BsSelect } from '@workspace/ui/components/Select'
import React from 'react'

const languages = [
    { id: 1, name: 'English' },
    { id: 2, name: 'Spanish' },
    { id: 3, name: 'French' },
    { id: 4, name: 'German' },
    { id: 5, name: 'Italian' },
]

export function SelectWithClearButton() {
    return (
        <div className="space-y-4 w-full">
            <BsSelect options={languages} isClearable />
        </div>
    )
}

In Form

'use client'

import { useForm } from 'react-hook-form'
import { toast } from '@workspace/ui/components/Sonner'

import { Button } from '@workspace/ui/components/Button'
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@workspace/ui/components/Form'
import { BsSelect } from '@workspace/ui/components/Select'
import { z } from '@workspace/lib/validation'

interface FormValues {
    languages: Array<string>
    role: string
}

const languageOptions = [
    { id: 'en', name: 'English' },
    { id: 'es', name: 'Spanish' },
    { id: 'fr', name: 'French' },
    { id: 'de', name: 'German' },
    { id: 'it', name: 'Italian' },
]

const roleOptions = [
    { id: 'admin', name: 'Admin' },
    { id: 'user', name: 'User' },
]

export function SelectForm() {
    const form = useForm<FormValues>({
        defaultValues: {
            role: roleOptions[0].id,
        },
    })

    function onSubmit(data: FormValues) {
        toast.neutral({
            title: 'You submitted the following values',
            description: (
                <pre>
                    <code>{JSON.stringify(data, null, 2)}</code>
                </pre>
            ),
        })
    }

    return (
        <Form {...form}>
            <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3 w-full">
                <FormField
                    control={form.control}
                    name="role"
                    rules={{ validate: z.string().min(1).validateFn() }}
                    render={({ field }) => (
                        <FormItem>
                            <FormLabel>Role</FormLabel>
                            <FormControl>
                                <BsSelect isClearable options={roleOptions} {...field} />
                            </FormControl>
                            <FormMessage />
                        </FormItem>
                    )}
                />
                <FormField
                    control={form.control}
                    name="languages"
                    render={({ field }) => (
                        <FormItem>
                            <FormLabel>Language</FormLabel>
                            <FormControl>
                                <BsSelect selectionMode="multiple" options={languageOptions} {...field} />
                            </FormControl>
                            <FormMessage />
                        </FormItem>
                    )}
                />
                <div className="grid grid-cols-2 gap-2 py-2">
                    <Button variant="outline">Cancel</Button>
                    <Button type="submit">Save</Button>
                </div>
            </form>
        </Form>
    )
}