# Hooks
**Category**: react
**URL**: https://www.heroui.com/docs/react/migration/hooks
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/migration/hooks.mdx
> Migration guide for HeroUI hooks from v2 to v3
***
Refer to the [v3 component documentation](/docs/components-list) for complete API reference. This guide focuses on migrating hooks from HeroUI v2.
## Overview
HeroUI v3 removes most component hooks that existed in v2, replacing them with compound components and a new hook for overlay state management. This guide covers:
- Component hooks removal (useSwitch, useInput, useCheckbox, etc.)
- useDisclosure → useOverlayState migration
- Migration strategies and examples
## Component Hooks Removal
HeroUI v2 provided component hooks (like `useSwitch`, `useInput`, `useCheckbox`, etc.) that returned prop getters (`getBaseProps`, `getWrapperProps`, `getThumbProps`, etc.) to customize component structure when users couldn't directly modify inner child components. HeroUI v3 solves this with compound components, eliminating the need for hooks.
### Why Hooks Existed in v2
In v2, components had fixed internal structures. To customize these structures, users needed to use hooks that provided prop getters. For example, `useSwitch` returned `getBaseProps()`, `getWrapperProps()`, `getThumbProps()`, etc., which users could spread onto custom elements to build their own Switch structure.
### v3 Solution: Compound Components
v3 uses compound component patterns that give you direct access to component parts. Instead of using hooks with prop getters, you compose components directly using subcomponents like `Switch.Control`, `Switch.Thumb`, `Checkbox.Control`, `Checkbox.Indicator`, etc.
### Migration Strategy
1. **Identify hook usage**: Search your codebase for imports from `@heroui/react` that include hook names (`useSwitch`, `useInput`, `useCheckbox`, `useRadio`, etc.)
2. **Replace with compound components**: Instead of using hooks with prop getters, use the compound component pattern
3. **Preserve original structure**: When migrating, try to keep the same component structure you had with hooks. For example:
- If you used `useSwitch` to create a switch **without** a thumb, don't add `Switch.Thumb` in v3
- If you used `useCheckbox` to create a checkbox **without** an indicator, don't add `Checkbox.Indicator` in v3
- Only include the subcomponents that were actually used in your hook-based implementation
4. **Reference component guides**: Check individual component migration guides for specific examples
### Key Differences
- **v2**: Hooks provided prop getters to customize fixed component structures
- **v3**: Compound components allow direct composition of component parts
### Preserving Structure Example
**v2: Switch without thumb**
```tsx
import { useSwitch } from "@heroui/react";
function CustomSwitch() {
const { getBaseProps } = useSwitch();
return (
{/* No thumb element */}
);
}
```
**v3: Equivalent structure**
```tsx
import { Switch } from "@heroui/react";
function CustomSwitch() {
return (
{/* No Switch.Thumb - preserving the original structure */}
);
}
```
For detailed migration examples for specific components, see the individual component migration guides.
## useDisclosure → useOverlayState
The `useDisclosure` hook from v2 has been replaced with `useOverlayState` in v3. This hook manages open/close state for modals, popovers, and other overlay components.
### v2: useDisclosure
**API:**
```tsx
const {isOpen, onOpen, onClose, onOpenChange, isControlled, getButtonProps, getDisclosureProps} = useDisclosure({
isOpen?: boolean;
defaultOpen?: boolean;
onClose?(): void;
onOpen?(): void;
onChange?(isOpen: boolean | undefined): void;
id?: string;
});
```
**Example:**
```tsx
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button, useDisclosure } from "@heroui/react";
export default function App() {
const {isOpen, onOpen, onOpenChange} = useDisclosure();
return (
<>
TitleContent
>
);
}
```
### v3: useOverlayState
**API:**
```tsx
const state = useOverlayState({
isOpen?: boolean;
defaultOpen?: boolean;
onOpenChange?: (isOpen: boolean) => void;
});
// Returns:
// {
// isOpen: boolean;
// open(): void;
// close(): void;
// toggle(): void;
// setOpen(isOpen: boolean): void;
// }
```
**Example:**
```tsx
import { Modal, Button, useOverlayState } from "@heroui/react";
export default function App() {
const state = useOverlayState();
return (
{({close}) => (
<>
TitleContent
>
)}
);
}
```
### Migration Guide
#### Basic Migration
**v2:**
```tsx
const {isOpen, onOpen, onClose, onOpenChange} = useDisclosure();
```
**v3:**
```tsx
const state = useOverlayState();
// Use state.open(), state.close(), state.toggle(), state.setOpen(boolean)
```
#### Controlled State
**v2:**
```tsx
const {isOpen, onOpenChange} = useDisclosure({
isOpen: controlledIsOpen,
onChange: (isOpen) => setControlledIsOpen(isOpen)
});
```
**v3:**
```tsx
const state = useOverlayState({
isOpen: controlledIsOpen,
onOpenChange: setControlledIsOpen
});
```
#### Uncontrolled State
**v2:**
```tsx
const {isOpen, onOpen, onClose} = useDisclosure({
defaultOpen: false
});
```
**v3:**
```tsx
const state = useOverlayState({
defaultOpen: false
});
// Use state.open(), state.close(), state.toggle()
```
### API Differences
| v2 (useDisclosure) | v3 (useOverlayState) | Notes |
|-------------------|---------------------|-------|
| `isOpen` | `isOpen` | Same |
| `onOpen()` | `open()` | Renamed method |
| `onClose()` | `close()` | Renamed method |
| `onOpenChange()` | `toggle()` | New method for toggling |
| `onOpenChange` (prop) | `setOpen(boolean)` | Different API |
| `isControlled` | - | Removed (handled internally) |
| `getButtonProps()` | - | Removed (use compound components) |
| `getDisclosureProps()` | - | Removed (use compound components) |
### Benefits of useOverlayState
- **Cleaner API**: Dedicated methods (`open()`, `close()`, `toggle()`) instead of callbacks
- **Simpler state management**: Works seamlessly with both controlled and uncontrolled patterns
- **Better TypeScript support**: Improved type inference and autocomplete
- **Consistent with React Aria**: Aligns with React Aria Components patterns
### Alternative: useState
For simple cases, you can also use React's `useState` directly:
```tsx
import { useState } from "react";
import { Modal, Button } from "@heroui/react";
export default function App() {
const [isOpen, setIsOpen] = useState(false);
return (
{/* content */}
);
}
```
However, `useOverlayState` provides a cleaner API with dedicated methods for common operations.
## Removed Hooks
The following hooks from v2 have been removed in v3:
- **useDraggable**: Removed
- **useClipboard**: Removed
- **usePagination**: Removed
- **useToast**: Removed
## Summary
- **Component hooks** (`useSwitch`, `useInput`, etc.) → Use **compound components** instead
- **useDisclosure** → Use **useOverlayState** for overlay state management
- **useOverlayState** provides a cleaner API with `open()`, `close()`, `toggle()`, and `setOpen()` methods
- **Removed hooks**: `useDraggable`, `useClipboard`, `usePagination`, `useToast` are no longer available
- For simple cases, `useState` can be used directly, but `useOverlayState` offers better ergonomics
For component-specific hook migration examples, refer to the individual component migration guides.