Gecko UIGecko UI

RHFSwitch

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

You are reading the v1 docs. v2 renamed several props and replaced GeckoUIPortal with GeckoUIProvider. Read this page in v2.

Live examples are only rendered in the v2 docs.

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

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

<RHFSwitch name="status" value="yes" uncheckedValue="no" />

With Number Values

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

With Object Values

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

Different Sizes

<RHFSwitch name="small" size="sm" />
<RHFSwitch name="medium" size="md" />

Disabled State

<RHFSwitch name="disabledOn" disabled />
<RHFSwitch name="disabledOff" disabled />

With Validation (Zod)

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

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