Forms
Checkbox.
A square toggle for yes or no choices, with checked, indeterminate and disabled states.
Other players can find your site from the Lantern Hub front page.
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
export default function CheckboxDemo() {
return (
<div className="flex flex-col gap-6">
<div className="flex items-center gap-3">
<Checkbox id="cb-terms" />
<Label htmlFor="cb-terms">Accept the hub rules</Label>
</div>
<div className="flex items-start gap-3">
<Checkbox id="cb-listed" defaultChecked />
<div className="grid gap-1.5">
<Label htmlFor="cb-listed">List in the directory</Label>
<p className="max-w-xs text-[13px] text-muted-foreground">
Other players can find your site from the Lantern Hub front page.
</p>
</div>
</div>
</div>
);
}Installation#
With the CLI
$npx lanterncn add checkboxThis also installs the Lantern theme and any Lantern UI components it depends on. The shadcn CLI works directly too: npx shadcn@latest add httptim/lantern-ui/checkbox. See Installation if your project is not set up yet.
Manually
Install the dependencies
npm install radix-ui lucide-reactCopy the source into your project
components/ui/checkbox.tsx"use client"; import * as React from "react"; import { Checkbox as CheckboxPrimitive } from "radix-ui"; import { CheckIcon, MinusIcon } from "lucide-react"; import { cn } from "@/lib/utils"; function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Root>) { return ( <CheckboxPrimitive.Root data-slot="checkbox" className={cn( "peer group/checkbox relative size-[18px] shrink-0 cursor-pointer rounded-sm border border-input bg-background/40 text-primary-foreground transition-[border-color,background-color,box-shadow] outline-none", "after:absolute after:-inset-2 hover:border-muted-foreground", "focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-ring/25", "data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary", "aria-invalid:border-destructive aria-invalid:ring-destructive/20 disabled:cursor-not-allowed disabled:opacity-50", className, )} {...props} > <CheckboxPrimitive.Indicator data-slot="checkbox-indicator" className="flex items-center justify-center text-current [&_svg]:size-3.5 [&_svg]:stroke-[3]" > <CheckIcon className="group-data-[state=indeterminate]/checkbox:hidden" /> <MinusIcon className="hidden group-data-[state=indeterminate]/checkbox:block" /> </CheckboxPrimitive.Indicator> </CheckboxPrimitive.Root> ); } export { Checkbox };Update the import paths to match your project
The source imports
cnfrom@/lib/utils.
Usage#
import { Checkbox } from "@/components/ui/checkbox";<div className="flex items-center gap-3">
<Checkbox id="terms" />
<Label htmlFor="terms">Accept the hub rules</Label>
</div>Pass checked="indeterminate" to show a dash, for example on a select-all box when only some rows are checked.
Examples#
Disabled and indeterminate
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
export default function CheckboxDisabled() {
return (
<div className="flex flex-col gap-4">
<div className="flex items-center gap-3">
<Checkbox id="cb-dis-1" disabled />
<Label htmlFor="cb-dis-1">Mirror to a second server</Label>
</div>
<div className="flex items-center gap-3">
<Checkbox id="cb-dis-2" disabled defaultChecked />
<Label htmlFor="cb-dis-2">Keep the site online (required)</Label>
</div>
<div className="flex items-center gap-3">
<Checkbox id="cb-ind" checked="indeterminate" />
<Label htmlFor="cb-ind">Some pages selected</Label>
</div>
</div>
);
}Checklist
2/4
"use client";
import * as React from "react";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
const tasks = [
{ id: "modem", label: "Attach a wireless modem" },
{ id: "install", label: "Run the Lantern installer" },
{ id: "claim", label: "Claim a hub address" },
{ id: "publish", label: "Publish your first page" },
];
export default function CheckboxChecklist() {
const [done, setDone] = React.useState<string[]>(["modem", "install"]);
const all = done.length === tasks.length;
return (
<div className="w-full max-w-sm rounded-lg border bg-card">
<div className="flex items-center justify-between gap-3 border-b px-4 py-3">
<div className="flex items-center gap-3">
<Checkbox
id="cl-all"
checked={all ? true : done.length ? "indeterminate" : false}
onCheckedChange={() => setDone(all ? [] : tasks.map((t) => t.id))}
/>
<Label htmlFor="cl-all" className="font-mono text-[10px] tracking-[0.2em] text-success uppercase">
Setup checklist
</Label>
</div>
<span className="font-mono text-[11px] text-muted-foreground">
{done.length}/{tasks.length}
</span>
</div>
<ul className="grid gap-3.5 p-4">
{tasks.map((task) => {
const checked = done.includes(task.id);
return (
<li key={task.id} className="flex items-center gap-3">
<Checkbox
id={`cl-${task.id}`}
checked={checked}
onCheckedChange={(v) =>
setDone((d) => (v === true ? [...d, task.id] : d.filter((x) => x !== task.id)))
}
/>
<Label
htmlFor={`cl-${task.id}`}
className={checked ? "text-muted-foreground line-through decoration-muted-foreground/60" : undefined}
>
{task.label}
</Label>
</li>
);
})}
</ul>
</div>
);
}