Quiero que el glyph para el estado indeterminate de un Checkbox de shadcn/ui con Radix UI sea una raya horizontal.
Para lograr que el checkbox de shadcn/ui (que utiliza Radix UI) muestre una raya horizontal en el estado indeterminate, debemos modificar el componente para que detecte dicho estado y renderice un icono diferente al de verificación (Check).
He preparado una versión completa y funcional del componente Checkbox junto con un ejemplo de uso para que puedas probarlo directamente.
Checkbox de Shadcn con Estado Indeterminado
Feb 28, 1:45 PMimport React, { useState, useEffect } from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check, Minus } from "lucide-react"
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
// Utilidad para manejar clases de Tailwind
function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
/**
* Componente Checkbox modificado para soportar el glifo de raya horizontal
* en estado 'indeterminate'.
*/
const Checkbox = React.forwardRef(({ className, checked, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 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
)}
checked={checked}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
{checked === "indeterminate" ? (
<Minus className="h-3.5 w-3.5 stroke-[3]" />
) : (
<Check className="h-3.5 w-3.5 stroke-[3]" />
)}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName
// --- Ejemplo de Implementación ---
const App = () => {
// El estado puede ser true, false o "indeterminate"
const [status, setStatus] = useState("indeterminate")
const toggleStatus = () => {
if (status === true) setStatus(false)
else if (status === false) setStatus("indeterminate")
else setStatus(true)
}
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-slate-950 text-white p-6">
<div className="bg-slate-900 p-10 rounded-xl border border-slate-800 shadow-xl space-y-6 w-full max-w-md">
<h2 className="text-xl font-semibold text-center mb-4">Estado del Checkbox</h2>
<div className="flex items-center space-x-3 p-4 bg-slate-800/50 rounded-lg border border-slate-700">
<Checkbox
id="terms"
checked={status}
onCheckedChange={(val) => setStatus(val)}
/>
<label
htmlFor="terms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 cursor-pointer"
>
Aceptar términos y condiciones
</label>
</div>
<div className="grid grid-cols-1 gap-2">
<button
onClick={toggleStatus}
className="px-4 py-2 bg-blue-600 hover:bg-blue-500 rounded-md text-sm transition-colors"
>
Alternar estado (Ciclo: Indet {'->'} On {'->'} Off)
</button>
<div className="text-center mt-4">
<span className="text-xs text-slate-400 uppercase tracking-widest">Valor actual:</span>
<code className="block mt-1 text-blue-400 font-mono text-lg">
{JSON.stringify(status)}
</code>
</div>
</div>
<div className="pt-4 border-t border-slate-700">
<p className="text-xs text-slate-500 text-center">
Nota: Se usa el icono <strong>Minus</strong> de Lucide cuando el valor es <code className="text-slate-300">"indeterminate"</code>.
</p>
</div>
</div>
</div>
)
}
export default App
He realizado los siguientes cambios clave para que funcione:
Icono Condicional: Dentro de CheckboxPrimitive.Indicator, he añadido una lógica que verifica si checked === "indeterminate". Si es así, renderiza el icono Minus (la raya horizontal); de lo contrario, renderiza el Check.
Estilos de Datos: He añadido data-[state=indeterminate]:bg-primary en las clases de Tailwind del Root. Radix UI asigna automáticamente este atributo data-state cuando el prop checked es exactamente el string "indeterminate".
Grosor del Trazo: He usado stroke-[3] en el componente Minus para que visualmente tenga un peso similar al icono de verificación por defecto de Radix.
No hay comentarios:
Publicar un comentario