useToggle
Simple React hook for managing boolean state with convenient toggle functions for common operations.
The useToggle hook provides an easy way to manage boolean state with additional utility functions for common operations like toggling, setting true/false explicitly. It's perfect for modals, feature flags, loading states, and any boolean-based UI interactions.
Basic Usage
import { useToggle } from 'light-hooks';
function Modal() {
  const { value: isOpen, toggle, setTrue: open, setFalse: close } = useToggle(false);
  return (
    <div>
      <button onClick={open}>Open Modal</button>
      
      {isOpen && (
        <div className="modal">
          <div className="modal-content">
            <h2>Modal Content</h2>
            <p>This is a modal dialog.</p>
            <button onClick={close}>Close</button>
            <button onClick={toggle}>Toggle</button>
          </div>
        </div>
      )}
    </div>
  );
}
API Reference
Parameters
| Parameter | Type | Description | 
|---|---|---|
initialValue | boolean | The initial boolean value (optional, defaults to false) | 
Return Value
interface UseToggleReturn {
  value: boolean;              // Current boolean value
  toggle: () => void;          // Function to toggle the value
  setTrue: () => void;         // Function to set the value to true
  setFalse: () => void;        // Function to set the value to false
  setValue: (value: boolean) => void;  // Function to set a specific value
}
Examples
Feature Toggles and Settings
function Settings() {
  const { value: darkMode, toggle: toggleDarkMode } = useToggle(false);
  const { value: notifications, setValue: setNotifications } = useToggle(true);
  const { value: autoSave, setTrue: enableAutoSave, setFalse: disableAutoSave } = useToggle(true);
  return (
    <div className="settings">
      <h3>Application Settings</h3>
      
      <div className="setting-item">
        <label>
          <input
            type="checkbox"
            checked={darkMode}
            onChange={toggleDarkMode}
          />
          Dark Mode
        </label>
      </div>
      
      <div className="setting-item">
        <label>
          <input
            type="checkbox"
            checked={notifications}
            onChange={(e) => setNotifications(e.target.checked)}
          />
          Enable Notifications
        </label>
      </div>
      
      <div className="setting-item">
        <label>Auto Save</label>
        <div>
          <button 
            onClick={enableAutoSave}
            className={autoSave ? 'active' : ''}
          >
            On
          </button>
          <button 
            onClick={disableAutoSave}
            className={!autoSave ? 'active' : ''}
          >
            Off
          </button>
        </div>
      </div>
    </div>
  );
}
Loading States
function DataComponent() {
  const [data, setData] = useState(null);
  const { value: loading, setTrue: startLoading, setFalse: stopLoading } = useToggle(false);
  const { value: error, setTrue: showError, setFalse: hideError } = useToggle(false);
  const fetchData = async () => {
    startLoading();
    hideError();
    
    try {
      const response = await fetch('/api/data');
      if (!response.ok) throw new Error('Failed to fetch');
      
      const result = await response.json();
      setData(result);
    } catch (err) {
      showError();
      console.error('Fetch error:', err);
    } finally {
      stopLoading();
    }
  };
  return (
    <div>
      <button onClick={fetchData} disabled={loading}>
        {loading ? 'Loading...' : 'Fetch Data'}
      </button>
      
      {error && (
        <div className="error">
          <p>Failed to load data</p>
          <button onClick={hideError}>Dismiss</button>
        </div>
      )}
      
      {data && (
        <div className="data">
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}
Sidebar and Navigation
function Layout({ children }: { children: React.ReactNode }) {
  const { value: sidebarOpen, toggle: toggleSidebar, setFalse: closeSidebar } = useToggle(false);
  const { value: mobileMenuOpen, toggle: toggleMobileMenu } = useToggle(false);
  return (
    <div className="layout">
      <header>
        <button onClick={toggleSidebar} className="sidebar-toggle">
          β° Menu
        </button>
        <button onClick={toggleMobileMenu} className="mobile-menu-toggle">
          π± Mobile Menu
        </button>
      </header>
      
      <div className="layout-content">
        {sidebarOpen && (
          <aside className="sidebar">
            <nav>
              <a href="/" onClick={closeSidebar}>Home</a>
              <a href="/about" onClick={closeSidebar}>About</a>
              <a href="/contact" onClick={closeSidebar}>Contact</a>
            </nav>
            <button onClick={closeSidebar}>Close Sidebar</button>
          </aside>
        )}
        
        <main className="main-content">
          {children}
        </main>
      </div>
      
      {mobileMenuOpen && (
        <div className="mobile-menu-overlay">
          <div className="mobile-menu">
            <button onClick={toggleMobileMenu}>β Close</button>
            <nav>
              <a href="/">Home</a>
              <a href="/about">About</a>
              <a href="/contact">Contact</a>
            </nav>
          </div>
        </div>
      )}
    </div>
  );
}
Form Validation and States
function ContactForm() {
  const [formData, setFormData] = useState({ name: '', email: '', message: '' });
  const { value: isSubmitting, setTrue: startSubmitting, setFalse: stopSubmitting } = useToggle(false);
  const { value: showSuccess, setTrue: showSuccessMessage, setFalse: hideSuccess } = useToggle(false);
  const { value: showValidation, setTrue: enableValidation } = useToggle(false);
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    enableValidation();
    
    if (!formData.name || !formData.email) {
      return; // Show validation errors
    }
    
    startSubmitting();
    
    try {
      await submitForm(formData);
      showSuccessMessage();
      setFormData({ name: '', email: '', message: '' });
      
      // Hide success message after 3 seconds
      setTimeout(hideSuccess, 3000);
    } catch (error) {
      console.error('Submit error:', error);
    } finally {
      stopSubmitting();
    }
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <input
          type="text"
          placeholder="Name"
          value={formData.name}
          onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
        />
        {showValidation && !formData.name && (
          <span className="error">Name is required</span>
        )}
      </div>
      
      <div>
        <input
          type="email"
          placeholder="Email"
          value={formData.email}
          onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
        />
        {showValidation && !formData.email && (
          <span className="error">Email is required</span>
        )}
      </div>
      
      <textarea
        placeholder="Message"
        value={formData.message}
        onChange={(e) => setFormData(prev => ({ ...prev, message: e.target.value }))}
      />
      
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Sending...' : 'Send Message'}
      </button>
      
      {showSuccess && (
        <div className="success">
          Message sent successfully!
        </div>
      )}
    </form>
  );
}
Advanced Examples
Accordion Component
function AccordionItem({ title, children }: { title: string; children: React.ReactNode }) {
  const { value: isExpanded, toggle } = useToggle(false);
  return (
    <div className="accordion-item">
      <button
        className="accordion-header"
        onClick={toggle}
        aria-expanded={isExpanded}
      >
        {title}
        <span className={`arrow ${isExpanded ? 'expanded' : ''}`}>βΌ</span>
      </button>
      
      {isExpanded && (
        <div className="accordion-content">
          {children}
        </div>
      )}
    </div>
  );
}
function FAQ() {
  return (
    <div className="accordion">
      <AccordionItem title="How do I get started?">
        <p>You can get started by installing our package and reading the documentation.</p>
      </AccordionItem>
      
      <AccordionItem title="Is it free to use?">
        <p>Yes, our library is completely free and open source.</p>
      </AccordionItem>
      
      <AccordionItem title="Can I contribute?">
        <p>Absolutely! We welcome contributions from the community.</p>
      </AccordionItem>
    </div>
  );
}
Multi-Step Form
function MultiStepForm() {
  const { value: step1Complete, setTrue: completeStep1 } = useToggle(false);
  const { value: step2Complete, setTrue: completeStep2 } = useToggle(false);
  const { value: showReview, setTrue: showReviewStep } = useToggle(false);
  const [formData, setFormData] = useState({
    personal: { name: '', email: '' },
    preferences: { newsletter: false, notifications: true },
    review: { terms: false }
  });
  const handleStep1Submit = (data: any) => {
    setFormData(prev => ({ ...prev, personal: data }));
    completeStep1();
  };
  const handleStep2Submit = (data: any) => {
    setFormData(prev => ({ ...prev, preferences: data }));
    completeStep2();
    showReviewStep();
  };
  return (
    <div className="multi-step-form">
      <div className="progress">
        <div className={`step ${step1Complete ? 'complete' : 'active'}`}>
          1. Personal Info
        </div>
        <div className={`step ${step2Complete ? 'complete' : step1Complete ? 'active' : ''}`}>
          2. Preferences
        </div>
        <div className={`step ${showReview ? 'active' : ''}`}>
          3. Review
        </div>
      </div>
      {!step1Complete && (
        <PersonalInfoStep onSubmit={handleStep1Submit} />
      )}
      
      {step1Complete && !step2Complete && (
        <PreferencesStep onSubmit={handleStep2Submit} />
      )}
      
      {showReview && (
        <ReviewStep data={formData} />
      )}
    </div>
  );
}
Feature Flags System
function FeatureFlagsProvider({ children }: { children: React.ReactNode }) {
  const { value: betaFeatures, toggle: toggleBetaFeatures } = useToggle(false);
  const { value: experimentalUI, toggle: toggleExperimentalUI } = useToggle(false);
  const { value: advancedMode, setValue: setAdvancedMode } = useToggle(false);
  const features = {
    betaFeatures,
    experimentalUI,
    advancedMode,
    toggleBetaFeatures,
    toggleExperimentalUI,
    setAdvancedMode
  };
  return (
    <FeatureFlagsContext.Provider value={features}>
      {children}
    </FeatureFlagsContext.Provider>
  );
}
function FeatureFlagsPanel() {
  const { 
    betaFeatures, 
    experimentalUI, 
    advancedMode,
    toggleBetaFeatures, 
    toggleExperimentalUI, 
    setAdvancedMode 
  } = useContext(FeatureFlagsContext);
  return (
    <div className="feature-flags-panel">
      <h3>Feature Flags</h3>
      
      <label>
        <input
          type="checkbox"
          checked={betaFeatures}
          onChange={toggleBetaFeatures}
        />
        Enable Beta Features
      </label>
      
      <label>
        <input
          type="checkbox"
          checked={experimentalUI}
          onChange={toggleExperimentalUI}
        />
        Experimental UI
      </label>
      
      <div>
        <span>Advanced Mode:</span>
        <button onClick={() => setAdvancedMode(true)}>Enable</button>
        <button onClick={() => setAdvancedMode(false)}>Disable</button>
      </div>
    </div>
  );
}
Theme Switcher
function ThemeSwitcher() {
  const { value: isDark, toggle: toggleTheme, setValue: setTheme } = useToggle(false);
  const { value: isSystemTheme, toggle: toggleSystemTheme } = useToggle(false);
  useEffect(() => {
    if (isSystemTheme) {
      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
      setTheme(mediaQuery.matches);
      
      const handler = (e: MediaQueryListEvent) => setTheme(e.matches);
      mediaQuery.addEventListener('change', handler);
      
      return () => mediaQuery.removeEventListener('change', handler);
    }
  }, [isSystemTheme, setTheme]);
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
  }, [isDark]);
  return (
    <div className="theme-switcher">
      <h3>Theme Settings</h3>
      
      <label>
        <input
          type="checkbox"
          checked={isSystemTheme}
          onChange={toggleSystemTheme}
        />
        Use System Theme
      </label>
      
      {!isSystemTheme && (
        <div className="manual-theme-controls">
          <button
            onClick={() => setTheme(false)}
            className={!isDark ? 'active' : ''}
          >
            βοΈ Light
          </button>
          <button
            onClick={() => setTheme(true)}
            className={isDark ? 'active' : ''}
          >
            π Dark
          </button>
          <button onClick={toggleTheme}>
            π Toggle
          </button>
        </div>
      )}
      
      <p>Current theme: {isDark ? 'Dark' : 'Light'}</p>
    </div>
  );
}
Comparison with useState
While you could achieve similar functionality with useState, useToggle provides convenience methods:
// Using useState (more verbose)
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(prev => !prev);
const open = () => setIsOpen(true);
const close = () => setIsOpen(false);
// Using useToggle (concise)
const { value: isOpen, toggle, setTrue: open, setFalse: close } = useToggle(false);
TypeScript Support
The hook is fully typed with comprehensive TypeScript interfaces:
const {
  value,      // boolean
  toggle,     // () => void
  setTrue,    // () => void
  setFalse,   // () => void
  setValue    // (value: boolean) => void
}: UseToggleReturn = useToggle(false);
Performance Tips
- Destructure with meaningful names: Use descriptive aliases for better code readability
 - Memoize callbacks: If passing toggle functions as props, consider using 
useCallback - Combine related toggles: Group related boolean states in a single component
 
Common Use Cases
- π UI States: Modals, dropdowns, sidebars, menus
 - βοΈ Settings: Feature toggles, preferences, configurations
 - π Forms: Validation states, submission states, field visibility
 - π¨ Themes: Dark/light mode, UI variants
 - π± Responsive: Mobile menu states, collapsible content
 - π Loading: Request states, progress indicators
 - π― Features: A/B testing, feature flags, experimental features
 
Best Practices
- Use descriptive aliases: 
const { value: isVisible, setTrue: show, setFalse: hide } - Group related toggles: Keep related boolean states in the same component
 - Initialize with meaningful defaults: Consider the most common initial state
 - Combine with other hooks: Works well with 
useEffect,useLocalStorage, etc. - Handle cleanup: Remember to clean up listeners or timers in effects
 
Perfect for any boolean state management in your React applications!