Checkbox
Un checkbox nativo donde toda la fila de la etiqueta es el objetivo y su texto nunca se selecciona.
Order alerts
Pick what reaches your phone.
Instalación
$ pnpm dlx shadcn@latest add @ssntl/checkboxUso
import { Checkbox, CheckboxLabel } from "@/components/ui/checkbox"
<div role="group" aria-labelledby="alertas-titulo">
<p id="alertas-titulo" className="text-heading">Alertas de pedidos</p>
<CheckboxLabel>
<Checkbox name="alertas" value="pedidos" defaultChecked />
Pedidos nuevos
</CheckboxLabel>
</div>- Un input nativo: se envía con el formulario y funciona con teclado y lectores de pantalla.
- La etiqueta envuelve la casilla, así toda la fila de 48px la activa; select-none evita que un doble clic seleccione el texto.
- Agrupa las casillas bajo un rol de encabezado (text-heading), no texto de cuerpo, unido con aria-labelledby.
- Los enlaces dentro de una etiqueta siguen funcionando; dales texto descriptivo.
Código
import * as React from "react"
import { Check } from "lucide-react"
import { cn } from "@/lib/utils"
// A native checkbox, so forms, keyboard and screen readers work as they
// should. The box is 24px; CheckboxLabel makes the whole 48px row the target.
function Checkbox({
className,
...props
}: Omit<React.ComponentProps<"input">, "type">) {
return (
<span
data-slot="checkbox"
className="inline-grid size-6 shrink-0 place-items-center"
>
<input
type="checkbox"
className={cn(
"peer col-start-1 row-start-1 size-6 cursor-pointer appearance-none rounded-xs border border-input bg-card",
"transition-[background-color,border-color] duration-(--duration-fast) ease-out checked:border-primary checked:bg-primary hover:border-foreground",
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
"disabled:cursor-not-allowed aria-invalid:border-destructive",
className
)}
{...props}
/>
{/* A heavier stroke than the 1.6 default, so the mark reads at 16px. */}
<Check
aria-hidden
strokeWidth={2}
className="pointer-events-none col-start-1 row-start-1 size-4 scale-50 text-primary-foreground opacity-0 transition-[opacity,scale] duration-(--duration-fast) ease-out peer-checked:scale-100 peer-checked:opacity-100 motion-reduce:scale-100"
/>
</span>
)
}
// The label wraps the box, so the text toggles it too. select-none keeps a
// quick double click from highlighting the words instead of checking twice.
function CheckboxLabel({ className, ...props }: React.ComponentProps<"label">) {
return (
<label
data-slot="checkbox-label"
className={cn(
"flex min-h-12 cursor-pointer items-center gap-3 text-body select-none has-disabled:cursor-not-allowed has-disabled:opacity-40",
className
)}
{...props}
/>
)
}
export { Checkbox, CheckboxLabel }