# 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
} label="Select animal">
Cat
```
```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`