# 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 ( <> Title Content ); } ``` ### 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}) => ( <> Title Content )} ); } ``` ### 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.