Skip to content

Instantly share code, notes, and snippets.

@abdmmar
Last active February 24, 2023 03:23
Show Gist options
  • Select an option

  • Save abdmmar/0189119c9308b5f07c5dd579af608e1e to your computer and use it in GitHub Desktop.

Select an option

Save abdmmar/0189119c9308b5f07c5dd579af608e1e to your computer and use it in GitHub Desktop.
Checkbox implementation using Radix UI, Tailwind CSS, CVA, and Tailwind Merge
import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
import { Label } from '@radix-ui/react-label'
import { HiCheck } from 'react-icons/hi'
import { tm } from '@/lib' // custom tailwind merge
import { Prettify } from '@/lib/types' // types utility to make union type more readable
import {
checkboxContainerVariants,
checkboxVariants,
CheckBoxVariantSizeProps,
labelVariants,
} from './checkbox.variant'
type CheckboxProps = Prettify<
{
label?: string
onChange: (checked: CheckboxPrimitive.CheckedState) => void
width?: 'full' | 'fit'
} & CheckboxPrimitive.CheckboxProps &
CheckBoxVariantSizeProps
>
const Checkbox = ({
id: _id,
label,
checked,
onChange,
className,
width,
disabled,
size,
}: CheckboxProps) => {
const id = _id || label
return (
<div className={checkboxContainerVariants({ width })}>
<Label className={labelVariants({ size, disabled })} htmlFor={id}>
{label}
</Label>
<CheckboxPrimitive.Root
id={id}
checked={checked}
disabled={disabled}
className={tm(checkboxVariants({ checked, size, className }))}
onCheckedChange={(checked) => {
if (checked !== 'indeterminate') {
onChange(checked)
}
}}
>
<CheckboxPrimitive.Indicator className="text-neutral-20">
<HiCheck />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
</div>
)
}
export default Checkbox
import { cva, VariantProps } from 'cva'
export const checkboxContainerVariants = cva('items-center', {
variants: {
width: {
full: 'flex justify-between',
fit: 'inline-flex justify-center',
},
},
defaultVariants: {
width: 'fit',
},
})
export const labelVariants = cva('mr-2', {
variants: {
size: {
// .text-m-regular {
// font-size: 14px;
// line-height: 20px;
// font-weight: 400;
// }
s: 'text-m-regular', // custom utility
m: 'text-m-regular',
l: 'text-l-regular',
xl: 'text-l-regular',
},
disabled: {
true: 'text-neutral-60',
false: 'text-neutral-90',
},
},
})
export const checkboxVariants = cva(
[
'peer',
'rounded-md',
'border',
'flex items-center justify-center',
'disabled:hover:border-neutral-50',
'disabled:border-neutral-50',
'disabled:cursor-not-allowed',
// 'disabled:', // disabled state
// 'data-[state=checked]:' // checked state
// 'disabled:data-[state=checked]', // disabled checked state
],
{
variants: {
checked: {
false: ['bg-white', 'border-neutral-50', 'hover:border-neutral-60'],
true: ['bg-teal-600', 'border-teal-600', 'hover:border-teal-800'],
indeterminate: [''],
},
size: {
s: 'w-5 h-5',
m: 'w-6 h-6',
l: 'w-7 h-7',
xl: 'w-8 h-8',
},
},
defaultVariants: {
checked: false,
size: 'm',
},
},
)
export type CheckBoxVariantProps = VariantProps<typeof checkboxVariants>
export type CheckBoxVariantSizeProps = Pick<CheckBoxVariantProps, 'size'>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment