FoodEase
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:

PropertyTypeDescription
statebooleanCurrent toggle state
toggle() => voidFunction to toggle state
setToggle(value: boolean) => voidFunction to set specific state

Examples

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>
  )
}
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 useCallback to 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 toggle and setToggle functions are memoized with useCallback
  • 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)

On this page