Checkbox

Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.

import { Checkbox } from 'cwl-ui'
 
export function Default() {
  return (
    <div>
      <Checkbox name="newsletter" value="subscribe">
        Children
      </Checkbox>
    </div>
  )
}

Component API

PropDefaultDescription
isSelectedfalsewhether or not the checkbox has been selected
isDisabledfalsewhether or not the checkbox is disabled
isIntermediatefalsewhether or not the checkbox is in an intermediate state

See React Aria Checkbox for more details.

Examples

Checkbox Disabled

import { Checkbox } from 'cwl-ui'
 
export function Disabled() {
  return (
    <div>
      <Checkbox isDisabled name="newsletter" value="subscribe">
        Children
      </Checkbox>
    </div>
  )
}

Checkbox Invalid

import { Checkbox } from 'cwl-ui'
 
export function Invalid() {
  return (
    <div>
      <Checkbox isInvalid name="newsletter" value="subscribe">
        Children
      </Checkbox>
    </div>
  )
}

Checkbox Intermediate

import React from 'react'
 
import { Checkbox } from 'cwl-ui'
 
type Checked = 'false' | 'true' | 'intermediate'
 
export function Intermediate() {
  let [checked, setChecked] = React.useState<Checked>('false')
 
  function handleOnChange() {
    if (checked === 'false') {
      setChecked('true')
    } else if (checked === 'true') {
      setChecked('intermediate')
    } else {
      setChecked('false')
    }
  }
 
  return (
    <div>
      <Checkbox
        isIndeterminate={checked === 'intermediate'}
        isSelected={checked === 'true'}
        onChange={handleOnChange}
        name="newsletter"
        value="subscribe"
      >
        Children
      </Checkbox>
    </div>
  )
}

Installation

To install, copy the code below and paste into your project.

'use client'
 
import { Check, Minus } from 'lucide-react'
import * as ReactAria from 'react-aria-components'
import { tv } from 'tailwind-variants'
 
import { focusRing } from './lib/utils'
 
const checkboxStyles = tv({
  base: 'flex gap-2 items-center group text-sm transition',
  variants: {
    isDisabled: {
      false: '[--color:theme(colors.slate.950)] text-[--color]',
      true: '[--color:theme(colors.slate.300)] text-[--color]',
    },
  },
})
 
const boxStyles = tv({
  extend: focusRing,
  base: 'w-5 h-5 flex-shrink-0 rounded flex items-center justify-center border-2 transition',
  variants: {
    isSelected: {
      false: 'bg-white [--color:theme(colors.slate.400)] border-[--color]',
      true: 'bg-[--color] border-[--color] [--color:theme(colors.slate.950)]',
    },
    isInvalid: {
      true: '[--color:theme(colors.red.700)]',
    },
    isDisabled: {
      true: '[--color:theme(colors.slate.300)]',
    },
  },
})
 
const iconStyles =
  'w-4 h-4 text-white [--color:theme(colors.slate.400)] group-disabled:text-[--color]'
 
export const Checkbox = (props: ReactAria.CheckboxProps) => {
  return (
    <ReactAria.Checkbox
      {...props}
      className={ReactAria.composeRenderProps(props.className, (className, renderProps) =>
        checkboxStyles({ ...renderProps, className }),
      )}
    >
      {({ isSelected, isIndeterminate, ...renderProps }) => {
        return (
          <>
            <div
              className={boxStyles({
                isSelected: isSelected || isIndeterminate,
                ...renderProps,
              })}
            >
              {isIndeterminate ? (
                <Minus aria-hidden className={iconStyles} />
              ) : isSelected ? (
                <Check aria-hidden className={iconStyles} />
              ) : null}
            </div>
            {props.children}
          </>
        )
      }}
    </ReactAria.Checkbox>
  )
}