# Select **Category**: react **URL**: https://www.heroui.com/docs/react/migration/select **Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/migration/(components)/select.mdx > Migration guide for Select from HeroUI v2 to v3 *** Refer to the [v3 Select documentation](/docs/react/components/select) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2. ## Structure Changes In v2, Select used a simple structure with props: ```tsx import { Select, SelectItem } from "@heroui/react"; export default function App() { return ( ); } ``` In v3, Select requires compound components and uses `ListBox` for items: ```tsx import { Select, Label, ListBox } from "@heroui/react"; export default function App() { return ( ); } ``` ## Key Changes ### 1. Component Structure **v2:** Simple Select with `SelectItem` children **v3:** Compound components (`Select.Trigger`, `Select.Value`, `Select.Indicator`, `Select.Popover`) with `ListBox` for items ### 2. Item Components **v2:** `SelectItem`, `SelectSection` **v3:** `ListBox.Item`, `ListBox.Section` (with `Header` for section titles and `Separator` between sections) ### 3. Prop Changes | v2 Prop | v3 Location | Notes | |---------|-------------|-------| | `selectedKeys` | `value` | Changed from Set/array to single value or array | | `onSelectionChange` | `onChange` | Renamed event handler | | `defaultSelectedKeys` | `defaultValue` | Renamed prop | | `label` | — | Use `Label` component | | `description` | — | Use `Description` component | | `errorMessage` | — | Use `FieldError` component | | `variant` | `variant` | Simplified to `primary` \| `secondary` only | | `color` | — | Removed (use Tailwind CSS) | | `size` | — | Removed (use Tailwind CSS) | | `radius` | — | Removed (use Tailwind CSS) | | `classNames` | — | Use `className` props on individual components | | `startContent` | — | Customize `Select.Trigger` directly | | `endContent` | — | Customize `Select.Trigger` directly | | `selectorIcon` | — | Customize `Select.Indicator` children | | `isClearable` | — | Implement clear button manually | | `renderValue` | — | Use `Select.Value` render prop | | `labelPlacement` | — | Labels are always outside | | `isRequired` | `isRequired` | Still exists | | `disabledKeys` | `disabledKeys` | Still exists | | `isOpen` | `isOpen` | New: controls the open state of the popover (controlled) | | `defaultOpen` | `defaultOpen` | New: sets the default open state of the popover (uncontrolled) | | `onOpenChange` | `onOpenChange` | New: handler called when the open state changes | | `selectionMode` | `selectionMode` | Still exists | | `disableAnimation` | — | Removed (animations handled differently) | | `popoverProps`, `listboxProps`, `scrollShadowProps` | — | Use props on `Select.Popover`, `ListBox`, etc. directly | ## Migration Examples ### Selection ```tsx import { useState } from "react"; {/* Single selection */} const [singleValue, setSingleValue] = useState(new Set([])); {/* Multiple selection */} const [multiValue, setMultiValue] = useState(new Set([])); ``` ```tsx import { useState } from "react"; import type { Key } from "@heroui/react"; {/* Single selection */} const [singleValue, setSingleValue] = useState(null); {/* Multiple selection */} const [multiValue, setMultiValue] = useState([]); ``` ### Form Validation ```tsx {/* With description */} {/* With validation */} ``` ```tsx import { Label, Description, FieldError } from "@heroui/react"; {/* With description */} {/* With validation */} ``` ### With Sections ```tsx import { Select, SelectItem, SelectSection } from "@heroui/react"; ``` ```tsx import { Select, Label, ListBox, Header, Separator } from "@heroui/react"; ``` ### Controlled Open State ```tsx {/* v2 did not have controlled open state */} ``` ```tsx import { useState } from "react"; import { Select, Label, ListBox } from "@heroui/react"; const [isOpen, setIsOpen] = useState(false); ``` ### Disabled Options ```tsx import { Select, SelectItem } from "@heroui/react"; ``` ```tsx import { Select, Label, ListBox } from "@heroui/react"; ``` ### Required ```tsx import { Select, SelectItem } from "@heroui/react"; ``` ```tsx import { Select, Label, ListBox } from "@heroui/react"; ``` ### Custom Indicator ```tsx ``` ```tsx ``` ## Component Anatomy The v3 Select follows this structure: ``` Select (Root) ├── Label (optional) ├── Select.Trigger │ ├── Select.Value │ └── Select.Indicator ├── Description (optional) ├── Select.Popover │ └── ListBox │ ├── ListBox.Item │ │ ├── Label (optional) │ │ ├── Description (optional) │ │ └── ListBox.ItemIndicator │ ├── ListBox.Section (optional) │ │ ├── Header (section title) │ │ └── ListBox.Item │ └── Separator (optional, between sections) └── FieldError (optional) ``` ## Important Notes ### Item Identification - **v2:** React's `key` was used for both list reconciliation and item identity for selection. - **v3:** Use `id` for state/focus and `textValue` for accessibility on `ListBox.Item`; keep React's `key` for list reconciliation. ### Selection Value Types - **v2:** `selectedKeys` was a `Set` or array - **v3:** `value` is `Key | null` for single selection or `Key[]` for multiple selection ### Clear Button The `isClearable` prop has been removed. To implement a clear button: ```tsx ``` ## Summary 1. **Component Structure**: Must use compound components (`Select.Trigger`, `Select.Value`, `Select.Indicator`, `Select.Popover`) 2. **Item Components**: `SelectItem` → `ListBox.Item`, `SelectSection` → `ListBox.Section` (use `Header` for section titles and `Separator` between sections) 3. **Label/Description/Error**: Use separate components instead of props 4. **Selection Props**: `selectedKeys`/`onSelectionChange` → `value`/`onChange` 5. **Controlled Open State**: New `isOpen`, `defaultOpen`, and `onOpenChange` props for controlling the popover open state 6. **Disabled Options**: `disabledKeys` prop still supported for disabling specific items 7. **Required**: `isRequired` prop still supported for marking the field as required 8. **Styling**: `variant` simplified to `primary` \| `secondary`; `color`, `size`, `radius` removed - use Tailwind for more 9. **ClassNames Removed**: Use `className` props on individual components 10. **Content Props Removed**: `startContent`, `endContent` - customize trigger directly 11. **Clear Button**: `isClearable` removed - implement manually 12. **Custom Value**: Use `Select.Value` render prop instead of `renderValue`