Hooks
useToggle
Hook for managing boolean toggle state
Overview
useToggle is a simple custom hook for managing boolean state with convenient toggle and setter functions.
Installation
## Installation
```bash
npx shadcn@latest add https://foodease-dev-registry.cap.reachcinema.io/r/v1/use-toggle.json
## Usage
### Basic Usage
```tsx
import useToggle from "@/hooks/useToggle"
export default function Example() {
const { state, toggle, setToggle } = useToggle()
return (
<div>
<p>State: {state ? "ON" : "OFF"}</p>
<button onClick={toggle}>Toggle</button>
</div>
)
}With Initial Value
import useToggle from "@/hooks/useToggle"
export default function Modal() {
const { state: isOpen, toggle, setToggle } = useToggle(false)
return (
<div>
<button onClick={() => setToggle(true)}>Open</button>
{isOpen && (
<div className="modal">
<p>Modal Content</p>
<button onClick={() => setToggle(false)}>Close</button>
<button onClick={toggle}>Toggle</button>
</div>
)}
</div>
)
}API Reference
useToggle
const { state, toggle, setToggle } = useToggle(initialValue?: boolean)Parameters:
initialValue?: boolean- Initial state value (default:false)
Returns:
| Property | Type | Description |
|---|---|---|
state | boolean | Current toggle state |
toggle | () => void | Function to toggle state |
setToggle | (value: boolean) => void | Function to set specific state |
Examples
Sidebar Toggle
import useToggle from "@/hooks/useToggle"
export default function Layout({ children }) {
const { state: isSidebarOpen, toggle: toggleSidebar } = useToggle(true)
return (
<div className="flex">
<button onClick={toggleSidebar}>☰</button>
{isSidebarOpen && (
<aside className="w-64 bg-gray-100">
<nav>{/* Navigation items */}</nav>
</aside>
)}
<main className="flex-1">{children}</main>
</div>
)
}Theme Switcher
import useToggle from "@/hooks/useToggle"
import { useEffect } from "react"
export default function ThemeToggle() {
const { state: isDark, toggle: toggleTheme } = useToggle(false)
useEffect(() => {
document.documentElement.classList.toggle("dark", isDark)
}, [isDark])
return (
<button onClick={toggleTheme}>
{isDark ? "🌙" : "☀️"}
</button>
)
}Show/Hide Password
import useToggle from "@/hooks/useToggle"
import { Input } from "@/components/ui/input"
export default function PasswordField() {
const { state: showPassword, toggle } = useToggle(false)
return (
<div className="relative">
<Input type={showPassword ? "text" : "password"} />
<button onClick={toggle} className="absolute right-2 top-2">
{showPassword ? "👁️" : "👁️🗨️"}
</button>
</div>
)
}Accordion
import useToggle from "@/hooks/useToggle"
export default function Accordion({ title, children }) {
const { state: isExpanded, toggle } = useToggle(false)
return (
<div className="border rounded">
<button
onClick={toggle}
className="w-full p-4 text-left flex justify-between"
>
<span>{title}</span>
<span>{isExpanded ? "−" : "+"}</span>
</button>
{isExpanded && (
<div className="p-4 border-t">
{children}
</div>
)}
</div>
)
}Menu Dropdown
import useToggle from "@/hooks/useToggle"
import { useRef, useEffect } from "react"
export default function Dropdown({ trigger, children }) {
const { state: isOpen, toggle, setToggle } = useToggle(false)
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
setToggle(false)
}
}
document.addEventListener("mousedown", handleClickOutside)
return () => document.removeEventListener("mousedown", handleClickOutside)
}, [setToggle])
return (
<div ref={ref} className="relative">
<button onClick={toggle}>{trigger}</button>
{isOpen && (
<div className="absolute top-full left-0 mt-2 bg-white shadow-lg rounded">
{children}
</div>
)}
</div>
)
}Feature Flags
import useToggle from "@/hooks/useToggle"
export default function FeatureToggler() {
const { state: enableAnalytics, setToggle: setAnalytics } = useToggle(true)
const { state: enableNotifications, setToggle: setNotifications } = useToggle(false)
const { state: enableBeta, setToggle: setBeta } = useToggle(false)
return (
<div className="space-y-4">
<label>
<input
type="checkbox"
checked={enableAnalytics}
onChange={(e) => setAnalytics(e.target.checked)}
/>
Enable Analytics
</label>
<label>
<input
type="checkbox"
checked={enableNotifications}
onChange={(e) => setNotifications(e.target.checked)}
/>
Enable Notifications
</label>
<label>
<input
type="checkbox"
checked={enableBeta}
onChange={(e) => setBeta(e.target.checked)}
/>
Enable Beta Features
</label>
</div>
)
}Loading State
import useToggle from "@/hooks/useToggle"
import { useState } from "react"
export default function DataFetcher() {
const { state: loading, setToggle: setLoading } = useToggle(false)
const [data, setData] = useState(null)
const fetchData = async () => {
setLoading(true)
try {
const response = await fetch("/api/data")
const result = await response.json()
setData(result)
} finally {
setLoading(false)
}
}
return (
<div>
<button onClick={fetchData} disabled={loading}>
{loading ? "Loading..." : "Fetch Data"}
</button>
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
</div>
)
}Benefits
- Simplicity: Clean API with three functions
- Type Safety: Fully typed with TypeScript
- Performance: Uses
useCallbackto prevent unnecessary re-renders - Flexibility: Can toggle or set specific values
- Reusability: Works for any boolean state management
Comparison
Without useToggle
const [isOpen, setIsOpen] = useState(false)
const toggle = () => setIsOpen(prev => !prev)With useToggle
const { state: isOpen, toggle, setToggle } = useToggle(false)Both approaches work, but useToggle provides:
- Consistent API across components
- No need to write toggle logic repeatedly
- Built-in setter function
Notes
- The
toggleandsetTogglefunctions are memoized withuseCallback - State updates follow React's batching rules
- Can be used with multiple instances in the same component
- No external dependencies
Type Definition
function useToggle(initialValue?: boolean): {
state: boolean
toggle: () => void
setToggle: (value: boolean) => void
}Dependencies
- React (
useState,useCallback)