Liqui Design

Checkbox

A flat control — a hairline box at rest, a solid accent fill when checked.

Loading…

Installation

npx shadcn@latest add https://liqui.design/r/checkbox.json

Installing more than one? Register the namespace once in components.json and drop the URLs:

components.json
{
  "registries": {
    "@liqui-design": "https://liqui.design/r/{name}.json"
  }
}
npx shadcn@latest add @liqui-design/checkbox

Usage

import { Checkbox, CheckboxLabel } from '@/components/ui/checkbox';
<CheckboxLabel>
  <Checkbox checked={checked} onCheckedChange={setChecked} />
  Show hidden files
</CheckboxLabel>

CheckboxLabel is a plain <label> row. It exists so the whole line is the hit area and so the text dims when the box inside is disabled — that last part is a has-[[data-disabled]] rule, not something the checkbox reaches out to do.

Notes

It is not glass

A checkbox is two solid fills and nothing else: --lq-control with a hairline at rest, --lq-accent when it is on. No backdrop filter, no displacement map, no specular arc.

That is the library's rule and it is Apple's: glass is for a surface you act through; a solid fill is for a control that carries a value. Checked is not a mood the material is in, it is a fact about your form, and a fact should not be refracting the wallpaper behind it. A checked box used to be a lens tinted with accent, which meant it was a slightly different blue on every backdrop it landed on.

Radio, Toggle and Switch are flat for the same reason, and Button's accent and danger variants are too.

'bg-[var(--lq-control)] shadow-[inset_0_0_0_1px_var(--lq-control-rim)]',
'data-[checked]:bg-[var(--lq-accent)] data-[checked]:shadow-none',

The hairline is an inset ring rather than a border, so the box stays exactly 20px and nothing reflows when it is checked. It goes away with the fill: a rim around a filled control is the bezel of a material that is no longer there.

Retune through --lq-control, --lq-control-rim and --lq-accent. They are ordinary theme tokens, and since nothing is composited over them, a plain background override works as well.

What used to be here

At 20px this was the smallest surface the lens was ever asked to render — the box was barely wider than its own bezel — and the docs used it as the canary for a global refraction that had been pushed too far. That fragility is gone with the lens, and so is a canvas-rendered displacement map and an SVG filter per box on screen. A form with forty checkboxes in it is now forty background colours.

If you want the canary back, Switch is the smallest lens left in the library.

Mixed is a different mark, not a different material

Inside a CheckboxGroup, a parent box goes into the mixed state when some but not all of its children are ticked. It takes the same accent fill with a dash instead of a tick — half-selected is a statement about the children, not a half-hearted version of being on.

The mark is read off the indicator's state rather than from an indeterminate prop, because nothing is passed down to a parent box: the group sets it.

On this page