Gecko UIGecko UI

RHFSwitch

Toggle switch component integrated with React Hook Form with custom value support

RHFSwitch

A controlled toggle switch component for React Hook Form. By default stores boolean values (true/false), but supports custom values of any type. Values maintain their original data types.

Installation

import { RHFSwitch } from '@geckoui/geckoui';

Basic Usage

Enable notifications
import { useForm, FormProvider } from 'react-hook-form';
import { RHFSwitch } from '@geckoui/geckoui';

function Example() {
  const methods = useForm({
    defaultValues: {
      enabled: false
    }
  });

  return (
    <FormProvider {...methods}>
      <div className="flex items-center gap-2">
        <RHFSwitch name="enabled" />
        <span>Enable notifications</span>
      </div>
    </FormProvider>
  );
}

Props API

Extends all props from Switch component plus:

PropTypeDefaultDescription
namestring-Field name (required)
controlControlAuto-injectedOptional: Pass explicitly for nested forms or custom form context
rulesRegisterOptions-Inline validation rules
valueunknown-Value when checked (if not provided, uses boolean)
uncheckedValueunknown-Value when unchecked (only with value prop)
size'sm' | 'md' | 'lg''md'Switch size
onChange(value: unknown) => void-Change callback
...restSwitchProps-All Switch component props

Examples

With Custom String Values

Accept terms and conditions
<RHFSwitch name="status" value="yes" uncheckedValue="no" />

With Number Values

Dark mode
<RHFSwitch name="mode" value={1} uncheckedValue={0} />

With Object Values

Advanced mode
<RHFSwitch
  name="settings"
  value={{ theme: 'dark', notifications: true }}
  uncheckedValue={{ theme: 'light', notifications: false }}
/>

Different Sizes

Small switch
Medium switch (default)
<RHFSwitch name="small" size="sm" />
<RHFSwitch name="medium" size="md" />

Disabled State

Disabled (On)
Disabled (Off)
<RHFSwitch name="disabledOn" disabled />
<RHFSwitch name="disabledOff" disabled />

With Validation (Zod)

I accept the terms and conditions
import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { RHFSwitch, RHFInputGroup } from '@geckoui/geckoui';

const schema = z.object({
  terms: z.literal(true, { message: 'You must accept the terms' })
});

function Example() {
  const methods = useForm({
    resolver: zodResolver(schema),
    mode: 'onBlur',
    defaultValues: { terms: false }
  });

  return (
    <FormProvider {...methods}>
      <RHFInputGroup required>
        <div className="flex items-center gap-2">
          <RHFSwitch name="terms" />
          <span>I accept the terms and conditions</span>
        </div>
      </RHFInputGroup>
    </FormProvider>
  );
}

Complete Form Example

Email notifications
Marketing emails
Dark mode
Enable two-factor authentication
import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { RHFSwitch, RHFInputGroup, Button } from '@geckoui/geckoui';

const schema = z.object({
  notifications: z.boolean(),
  marketing: z.boolean(),
  darkMode: z.boolean(),
  twoFactor: z.literal(true, { message: 'Two-factor authentication is required' })
});

function FormExample() {
  const methods = useForm({
    resolver: zodResolver(schema),
    mode: 'onBlur',
    defaultValues: {
      notifications: true,
      marketing: false,
      darkMode: false,
      twoFactor: false
    }
  });

  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit(console.log)}>
        <div className="space-y-3">
          <div className="flex items-center justify-between">
            <span>Email notifications</span>
            <RHFSwitch name="notifications" />
          </div>
          <div className="flex items-center justify-between">
            <span>Marketing emails</span>
            <RHFSwitch name="marketing" />
          </div>
          <div className="flex items-center justify-between">
            <span>Dark mode</span>
            <RHFSwitch name="darkMode" />
          </div>
        </div>

        <RHFInputGroup required>
          <div className="flex items-center gap-2">
            <RHFSwitch name="twoFactor" />
            <span>Enable two-factor authentication</span>
          </div>
        </RHFInputGroup>

        <Button type="submit">Save Settings</Button>
      </form>
    </FormProvider>
  );
}

Inline Rules Validation

For simple validation, use the rules prop:

<RHFSwitch
  name="terms"
  rules={{ required: 'You must accept the terms' }}
/>

For complex forms, we recommend using a schema resolver (Zod, Yup) instead.

Value Behavior

Default (Boolean Mode)

When value prop is not provided, the switch toggles between true and false:

// Stores: true or false
<RHFSwitch name="enabled" />

Custom Values Mode

When value prop is provided:

  • Checked: Stores the value
  • Unchecked: Stores uncheckedValue (default: undefined)
// Stores: "yes" or "no"
<RHFSwitch name="status" value="yes" uncheckedValue="no" />

// Stores: 1 or 0
<RHFSwitch name="mode" value={1} uncheckedValue={0} />

// Stores: object or undefined
<RHFSwitch name="settings" value={{ enabled: true }} />

// Stores: first object or second object
<RHFSwitch
  name="config"
  value={{ theme: 'dark' }}
  uncheckedValue={{ theme: 'light' }}
/>

Value Type Preservation

RHFSwitch preserves the original value type:

// Boolean (default)
<RHFSwitch name="enabled" />
// Result: true or false

// String
<RHFSwitch name="status" value="active" uncheckedValue="inactive" />
// Result: "active" or "inactive"

// Number
<RHFSwitch name="level" value={10} uncheckedValue={0} />
// Result: 10 or 0

// Object
<RHFSwitch name="settings" value={{ a: 1 }} uncheckedValue={{ a: 0 }} />
// Result: { a: 1 } or { a: 0 }

// Array
<RHFSwitch name="permissions" value={['read', 'write']} uncheckedValue={[]} />
// Result: ['read', 'write'] or []

Error States

RHFSwitch doesn't apply error styling directly. Use RHFInputGroup to display errors:

<RHFInputGroup required>
  <div className="flex items-center gap-2">
    <RHFSwitch name="terms" />
    <span>Accept terms</span>
  </div>
</RHFInputGroup>

Tip: Use mode: 'onBlur' in useForm to validate on blur:

const methods = useForm({
  resolver: zodResolver(schema),
  mode: 'onBlur'
});

Keyboard Support

The switch supports full keyboard interaction:

  • Space or Enter: Toggle the switch
  • Tab: Move focus to/from the switch

Accessibility

  • Inherits all accessibility features from Switch component
  • Proper ARIA attributes
  • Keyboard accessible
  • Screen reader compatible
  • Disabled state properly communicated