# Checkbox / Checkbox

> coss ui checkboxes over a native checkbox. Includes “All” with a mixed state.

Page: https://componentes-lovat.vercel.app/c/checkbox/  
License: MIT · Design: coss ui (MIT) · checkbox.tsx  
Requires: tokens.css  
Context: ambos · Density: media · Tone: sobria

## Files

- Tokens (once): https://componentes-lovat.vercel.app/tokens.css
- HTML: https://componentes-lovat.vercel.app/raw/checkbox/checkbox.html
- CSS: https://componentes-lovat.vercel.app/raw/checkbox/checkbox.css
- JS: https://componentes-lovat.vercel.app/raw/checkbox/checkbox.js
- Everything in one file: https://componentes-lovat.vercel.app/r/checkbox.html

Dark theme: add class `dark` to `<html>`.

## When to use

- To choose several options.
- For a single agreement.

## When not to use

- If only one is allowed: use radios.
- For instant settings: use a switch.

## Accessibility

Roles: checkbox, group

| Keys | Action |
|---|---|
| Espacio / Space | Checks or unchecks |

- The real input sits on top, invisible: screen readers and agents use a real checkbox.
- “All” uses indeterminate, announced as “mixed”.

## Code

```html
<fieldset class="c-checkbox-group" data-c-checkall>
  <legend class="c-checkbox-group__legend">Exportar</legend>
  <label class="c-label">
    <span class="c-checkbox"><input class="c-checkbox__input" type="checkbox" data-c-all><span class="c-checkbox__indicator"><svg class="c-checkbox__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5.252 12.7 10.2 18.63 18.748 5.37"/></svg><svg class="c-checkbox__dash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" aria-hidden="true"><path d="M5.252 12h13.496"/></svg></span></span>
    Todo
  </label>
  <div class="c-checkbox-group__items">
    <label class="c-label"><span class="c-checkbox"><input class="c-checkbox__input" type="checkbox" name="export" value="png" checked><span class="c-checkbox__indicator"><svg class="c-checkbox__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5.252 12.7 10.2 18.63 18.748 5.37"/></svg><svg class="c-checkbox__dash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" aria-hidden="true"><path d="M5.252 12h13.496"/></svg></span></span> Póster en PNG</label>
    <label class="c-label"><span class="c-checkbox"><input class="c-checkbox__input" type="checkbox" name="export" value="json"><span class="c-checkbox__indicator"><svg class="c-checkbox__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5.252 12.7 10.2 18.63 18.748 5.37"/></svg><svg class="c-checkbox__dash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" aria-hidden="true"><path d="M5.252 12h13.496"/></svg></span></span> Receta JSON</label>
    <label class="c-label"><span class="c-checkbox"><input class="c-checkbox__input" type="checkbox" name="export" value="palette"><span class="c-checkbox__indicator"><svg class="c-checkbox__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5.252 12.7 10.2 18.63 18.748 5.37"/></svg><svg class="c-checkbox__dash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" aria-hidden="true"><path d="M5.252 12h13.496"/></svg></span></span> Paleta de colores</label>
  </div>
</fieldset>
<label class="c-label c-label--top">
  <span class="c-checkbox"><input class="c-checkbox__input" type="checkbox" checked><span class="c-checkbox__indicator"><svg class="c-checkbox__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5.252 12.7 10.2 18.63 18.748 5.37"/></svg><svg class="c-checkbox__dash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" aria-hidden="true"><path d="M5.252 12h13.496"/></svg></span></span>
  <span class="c-label__text">Acepto los términos <span class="c-label__description">Al marcarla aceptas la licencia MIT.</span></span>
</label>
<label class="c-label"><span class="c-checkbox"><input class="c-checkbox__input" type="checkbox" disabled><span class="c-checkbox__indicator"><svg class="c-checkbox__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5.252 12.7 10.2 18.63 18.748 5.37"/></svg><svg class="c-checkbox__dash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" aria-hidden="true"><path d="M5.252 12h13.496"/></svg></span></span> Deshabilitado</label>
```

```css
/* checkbox · Componentes (MIRÓ Labs). Diseño de coss ui (MIT, © coss.com, antes Origin UI).
   Generado por tools/build_css.py desde checkbox.tw.json. No editar a mano. Necesita tokens.css. */
.c-checkbox__indicator{position:absolute}
.c-checkbox{position:relative}
.c-checkbox__indicator{inset:-1px}
.c-checkbox-group__legend{margin-bottom:calc(var(--spacing)*1)}
.c-checkbox__indicator{display:flex}
.c-checkbox-group{display:flex}
.c-checkbox{display:inline-flex}
.c-label{display:inline-flex}
.c-checkbox svg{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}
.c-checkbox{width:calc(var(--spacing)*4.5);height:calc(var(--spacing)*4.5);flex-shrink:0}
.c-checkbox-group{flex-direction:column}
.c-checkbox{align-items:center}
.c-checkbox__indicator{align-items:center}
.c-label{align-items:center}
.c-checkbox{justify-content:center}
.c-checkbox__indicator{justify-content:center}
.c-label{gap:calc(var(--spacing)*2)}
.c-checkbox-group{gap:calc(var(--spacing)*3)}
.c-checkbox{border-radius:.25rem}
.c-checkbox__indicator{border-radius:.25rem}
.c-checkbox{border-style:var(--tw-border-style);border-width:1px;border-color:var(--input);background-color:var(--background)}
.c-label{font-size:var(--text-base);line-height:calc(var(--spacing)*4.5)}
.c-checkbox-group__legend{font-size:var(--text-base);line-height:calc(var(--spacing)*4.5)}
.c-label__description{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}
.c-label{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}
.c-checkbox-group__legend{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}
.c-label__description{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}
.c-label{color:var(--foreground)}
.c-checkbox-group__legend{color:var(--foreground)}
.c-label__description{color:var(--muted-foreground)}
.c-checkbox__indicator{color:var(--primary-foreground)}
.c-checkbox{--tw-shadow-alpha:5%;--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
@supports (color:lab(0% 0 0)){
.c-checkbox{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,lab(0% 0 0/.05))}
}
.c-checkbox{--tw-ring-color:var(--ring);transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-outline-style:none;outline-style:none}
.c-checkbox:not(:is(.dark *)){background-clip:padding-box}
.c-checkbox:before{content:var(--tw-content);pointer-events:none;content:var(--tw-content);position:absolute;content:var(--tw-content);inset:calc(var(--spacing)*0);content:var(--tw-content);border-radius:3px}
.c-checkbox:not(:has(>.c-checkbox__input:disabled)):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))):not([aria-invalid=true]):before{content:var(--tw-content);--tw-shadow:0 1px var(--tw-shadow-color,#0000000a)}
@supports (color:color-mix(in lab, red, red)){
.c-checkbox:not(:has(>.c-checkbox__input:disabled)):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))):not([aria-invalid=true]):before{--tw-shadow:0 1px var(--tw-shadow-color,color-mix(in oklab,var(--color-black)4%,transparent))}
}
.c-checkbox:not(:has(>.c-checkbox__input:disabled)):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))):not([aria-invalid=true]):before{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
.c-checkbox:has(>.c-checkbox__input:focus-visible){--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color);--tw-ring-offset-color:var(--background)}
.c-checkbox[aria-invalid=true]{border-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-checkbox[aria-invalid=true]{border-color:color-mix(in oklab,var(--destructive)36%,transparent)}
}
.c-checkbox:has(>.c-checkbox__input:focus-visible)[aria-invalid=true]{border-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-checkbox:has(>.c-checkbox__input:focus-visible)[aria-invalid=true]{border-color:color-mix(in oklab,var(--destructive)64%,transparent)}
}
.c-checkbox:has(>.c-checkbox__input:focus-visible)[aria-invalid=true]{--tw-ring-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-checkbox:has(>.c-checkbox__input:focus-visible)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)48%,transparent)}
}
.c-checkbox__input:checked~.c-checkbox__indicator{background-color:var(--primary)}
.c-checkbox:has(>.c-checkbox__input:disabled){cursor:not-allowed;opacity:.64}
.c-checkbox__input:indeterminate~.c-checkbox__indicator{color:var(--foreground)}
.c-checkbox__input:not(:checked,:indeterminate)~.c-checkbox__indicator{display:none}
@media (min-width:40rem){
.c-checkbox svg{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}
.c-checkbox{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}
.c-label{font-size:var(--text-sm);line-height:calc(var(--spacing)*4)}
.c-checkbox-group__legend{font-size:var(--text-sm);line-height:calc(var(--spacing)*4)}
}
.c-checkbox:is(.dark *):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))){background-color:var(--input)}
@supports (color:color-mix(in lab, red, red)){
.c-checkbox:is(.dark *):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))){background-color:color-mix(in oklab,var(--input)32%,transparent)}
}
.c-checkbox:is(.dark *):not(:has(>.c-checkbox__input:disabled)):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))):not([aria-invalid=true]):before{content:var(--tw-content);--tw-shadow:0 -1px var(--tw-shadow-color,#ffffff0f)}
@supports (color:color-mix(in lab, red, red)){
.c-checkbox:is(.dark *):not(:has(>.c-checkbox__input:disabled)):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))):not([aria-invalid=true]):before{--tw-shadow:0 -1px var(--tw-shadow-color,color-mix(in oklab,var(--color-white)6%,transparent))}
}
.c-checkbox:is(.dark *):not(:has(>.c-checkbox__input:disabled)):not(:has(>.c-checkbox__input:is(:checked,:indeterminate))):not([aria-invalid=true]):before{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
.c-checkbox:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}
@supports (color:color-mix(in lab, red, red)){
.c-checkbox:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)24%,transparent)}
}
.c-checkbox:is(:has(>.c-checkbox__input:disabled),:has(>.c-checkbox__input:is(:checked,:indeterminate)),:has(>.c-checkbox__input[aria-invalid=true])){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}
/* propio */
.c-checkbox__input{position:absolute;inset:-1px;z-index:1;margin:0;opacity:0;cursor:pointer;appearance:none}
.c-checkbox__input:disabled{cursor:not-allowed}
.c-checkbox .c-checkbox__dash{display:none}
.c-checkbox__input:indeterminate~.c-checkbox__indicator .c-checkbox__check{display:none}
.c-checkbox__input:indeterminate~.c-checkbox__indicator .c-checkbox__dash{display:block}
.c-label{cursor:pointer}
.c-label:has(:disabled){cursor:not-allowed;opacity:.64}
.c-label--top{align-items:flex-start}
.c-label--top .c-checkbox{margin-top:1px}
.c-label__text{display:grid;gap:.25rem}
.c-checkbox-group__items{display:flex;flex-direction:column;gap:.75rem;padding-left:1.5rem}
fieldset.c-checkbox-group{border:0;margin:0;padding:0;min-width:0}
```

```js
/* Checkbox «Todo»: marca o desmarca el grupo y queda intermedio si solo hay algunos. */
(function () {
  const C = (window.Componentes = window.Componentes || {});

  function setup(set) {
    const all = set.querySelector('[data-c-all]');
    const items = [...set.querySelectorAll('input[type=checkbox]:not([data-c-all])')];
    if (!all || !items.length) return;
    const sync = () => {
      const on = items.filter((i) => i.checked).length;
      all.checked = on === items.length;
      all.indeterminate = on > 0 && on < items.length;
    };
    all.addEventListener('change', () => { items.forEach((i) => { if (!i.disabled) i.checked = all.checked; }); sync(); });
    items.forEach((i) => i.addEventListener('change', sync));
    sync();
  }

  function init(root) {
    (root || document).querySelectorAll('[data-c-checkall]:not([data-c-ready])').forEach((el) => {
      el.dataset.cReady = '';
      try { setup(el); } catch (e) { console.warn('[checkbox]', e); }
    });
  }

  C.checkbox = { init };
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => init());
  else init();
})();
```

## Credits

- coss ui (MIT) · checkbox.tsx: https://coss.com/ui
- W3C WAI-ARIA APG, Checkbox: https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/
