Checkbox
A control that allows the user to toggle between checked and not checked.
The Checkbox component is a control that allows users to toggle between checked and not checked states. It features bold borders and shadows that match the Things design system. Built from scratch using React and native HTML input elements. No dependencies on any UI library.
Code
TypeScript: Copy this code into components/ui/checkbox.tsx:
tsx
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
export interface CheckboxProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type"> {}
const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
({ className, checked, onChange, disabled, ...props }, ref) => {
const [isChecked, setIsChecked] = React.useState(checked ?? false)
React.useEffect(() => {
if (checked !== undefined) {
setIsChecked(checked)
}
}, [checked])
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (disabled) return
setIsChecked(e.target.checked)
onChange?.(e)
}
return (
<label
className={cn(
"relative inline-flex h-5 w-5 items-center justify-center cursor-pointer",
disabled && "opacity-50 cursor-not-allowed",
className
)}
>
<input
type="checkbox"
className="sr-only"
checked={isChecked}
onChange={handleChange}
disabled={disabled}
ref={ref}
{...props}
/>
<span
className={cn(
"flex h-5 w-5 items-center justify-center rounded-sm border-2 border-foreground bg-background transition-colors neobrutalism-shadow-sm",
isChecked && "bg-primary border-primary",
disabled && "cursor-not-allowed"
)}
>
{isChecked && (
<svg
className="h-3 w-3 text-primary-foreground"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
strokeWidth={3}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M5 13l4 4L19 7"
/>
</svg>
)}
</span>
</label>
)
}
)
Checkbox.displayName = "Checkbox"
export { Checkbox }JavaScript: Copy this code into components/ui/checkbox.jsx:
jsx
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
const Checkbox = React.forwardRef(
({ className, checked, onChange, disabled, ...props }, ref) => {
const [isChecked, setIsChecked] = React.useState(checked ?? false)
React.useEffect(() => {
if (checked !== undefined) {
setIsChecked(checked)
}
}, [checked])
const handleChange = (e) => {
if (disabled) return
setIsChecked(e.target.checked)
onChange?.(e)
}
return (
<label
className={cn(
"relative inline-flex h-5 w-5 items-center justify-center cursor-pointer",
disabled && "opacity-50 cursor-not-allowed",
className
)}
>
<input
type="checkbox"
className="sr-only"
checked={isChecked}
onChange={handleChange}
disabled={disabled}
ref={ref}
{...props}
/>
<span
className={cn(
"flex h-5 w-5 items-center justify-center rounded-sm border-2 border-foreground bg-background transition-colors neobrutalism-shadow-sm",
isChecked && "bg-primary border-primary",
disabled && "cursor-not-allowed"
)}
>
{isChecked && (
<svg
className="h-3 w-3 text-primary-foreground"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
strokeWidth={3}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M5 13l4 4L19 7"
/>
</svg>
)}
</span>
</label>
)
}
)
Checkbox.displayName = "Checkbox"
export { Checkbox }Usage
TypeScript:
tsx
import { Checkbox } from "@/components/ui/checkbox"
import { useState } from "react"
function MyComponent() {
const [checked, setChecked] = useState(false)
return (
<Checkbox
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
/>
)
}JavaScript:
jsx
import { Checkbox } from "@/components/ui/checkbox"
import { useState } from "react"
function MyComponent() {
const [checked, setChecked] = useState(false)
return (
<Checkbox
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
/>
)
}Make sure you also have the lib/utils.ts file with the cn helper function.