Indeterminate Checkbox

PreviousNext

An indeterminate checkbox component

Docs
shadcnui-blockscomponent

Preview

Loading preview…
components/customized/checkbox/checkbox-03.tsx
"use client";

import { cn } from "@/lib/utils";
import { Checkbox as CheckboxPrimitive } from "radix-ui";
import { CheckIcon, MinusIcon } from "lucide-react";
import * as React from "react";

// Replace the `Checkbox` component in `@components/ui/checkbox` with below component and use it here to support indeterminate.
const Checkbox = React.forwardRef<
  React.ElementRef<typeof CheckboxPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
  <CheckboxPrimitive.Root
    ref={ref}
    className={cn(
      "group peer h-4 w-4 shrink-0 rounded border border-primary shadow-sm focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=indeterminate]:bg-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:text-primary-foreground",
      className
    )}
    {...props}
  >
    <CheckboxPrimitive.Indicator
      className={cn("flex items-center justify-center text-current")}
    >
      <MinusIcon className="h-4 w-4 hidden group-data-[state=indeterminate]:block" />
      <CheckIcon className="h-4 w-4 hidden group-data-[state=checked]:block" />
    </CheckboxPrimitive.Indicator>
  </CheckboxPrimitive.Root>
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;

export default function IndeterminateCheckboxDemo() {
  const [checked, setChecked] = React.useState<
    Record<string, CheckboxPrimitive.CheckedState>
  >({
    child1: true,
    child2: false,
  });

  const handleCheckedChange = (
    name: string,
    checked: CheckboxPrimitive.CheckedState
  ) => {
    setChecked((prev) => ({
      ...prev,
      [name]: checked,
    }));
  };

  const handleParentCheckedChange = (
    checked: CheckboxPrimitive.CheckedState
  ) => {
    setChecked({
      child1: checked,
      child2: checked,
    });
  };

  return (
    <div className="space-y-4">
      <div className="flex items-center">
        <Checkbox
          id="parent"
          checked={
            checked.child1 === checked.child2 ? checked.child1 : "indeterminate"
          }
          onCheckedChange={handleParentCheckedChange}
        />
        <label
          htmlFor="parent"
          className="ml-2 text-sm font-medium leading-none"
        >
          Parent
        </label>
      </div>
      <div className="pl-6 space-y-2">
        <div className="flex items-center">
          <Checkbox
            id="child1"
            checked={checked.child1}
            onCheckedChange={(checked) =>
              handleCheckedChange("child1", checked)
            }
          />
          <label
            htmlFor="child1"
            className="ml-2 text-sm font-medium leading-none"
          >
            Child 1
          </label>
        </div>
        <div className="flex items-center">
          <Checkbox
            id="child2"
            checked={checked.child2}
            onCheckedChange={(checked) =>
              handleCheckedChange("child2", checked)
            }
          />
          <label
            htmlFor="child2"
            className="ml-2 text-sm font-medium leading-none"
          >
            Child 2
          </label>
        </div>
      </div>
    </div>
  );
}

Installation

npx shadcn@latest add @shadcnui-blocks/checkbox-03

Usage

import { Checkbox03 } from "@/components/checkbox-03"
<Checkbox03 />