Skip to content

Instantly share code, notes, and snippets.

@stephent
Last active December 19, 2022 10:03
Show Gist options
  • Save stephent/2ddacd523d14fa53eaa3324fe1d64669 to your computer and use it in GitHub Desktop.
Save stephent/2ddacd523d14fa53eaa3324fe1d64669 to your computer and use it in GitHub Desktop.
General purpose switch component using headlessui, tailwind and react-hook-form
import { useController, UseControllerProps } from "react-hook-form";
import { Switch } from '@headlessui/react'
type Props = {
label?: string;
enabledLabel?: string;
disabledLabel?: string;
title?: string;
};
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export const ControlledSwitch = (props: Props & UseControllerProps) => {
const { enabledLabel, disabledLabel, label, title } = props;
const { field: { value, onChange } } = useController(props);
return (
<Switch.Group as="div" className="flex items-center">
<>{(disabledLabel || label) &&
<Switch.Label as="span" className="mr-3">
<span className="text-sm font-medium text-gray-900">{disabledLabel || label}</span>
</Switch.Label>
}</>
<Switch
checked={value}
onChange={onChange}
title={title || ''}
className={classNames(
value ? 'bg-gray-700 hover:bg-gray-500' : 'bg-gray-200 hover:bg-gray-400',
'relative p-0 inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-100 focus:outline-none focus:ring-1 focus:ring-offset-2 focus:ring-gray-500'
)}
>
<span
aria-hidden="true"
className={classNames(
value ? 'translate-x-5' : 'translate-x-0',
'pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-100'
)}
/>
{title &&
<span className="sr-only">{title}</span>
}
</Switch>
{enabledLabel &&
<Switch.Label as="span" className="ml-3">
<span className="text-sm font-medium text-gray-900">{enabledLabel}</span>
</Switch.Label>
}
</Switch.Group>
)
};
@stephent
Copy link
Author

stephent commented Nov 24, 2022

Inspired by @jasonabullard 's List example. Refer to this for an example of how to use the component in a form.

Set label if you want a single label to the left of the switch. Set both enabledLabel and disabledLabel if you want value specific labels either side of the switch.

@kevindcode
Copy link

Thanks for creating this! 💪 Was just wondering how it's going to register the input element for the Switch component?

Looking at the docs here (https://headlessui.com/react/switch#using-with-html-forms), headlessui states that we should pass in a name prop so that it renders a hidden input element which acts as a form control.

Does this work without needing this additional input element (?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment