Checkbox

Checkbox Row

A checkbox whose target is the whole row — label and description included — not a 16px square in the corner. The tick is drawn in CSS; a native input holds the state.

  • checkbox
  • form
  • settings
  • toggle

Preview

1440pxHost theme

Use it with AI

  1. 1. Copy the link.
  2. 2. Write to your agent in your own words and drop the link into the sentence.
  3. 3. The agent opens the link and installs the component from the registry.

put this in the header: https://vibeui.ru/c/checkbox-001?lang=en

Show the full instructions

What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.

# Install and place "checkbox-001" (Checkbox Row) from VibeUI

## 1. Install first — do not skip, do not recreate
Run this exact command before writing any code:
npx shadcn@latest add https://vibeui.ru/r/checkbox-001.json

Registry item: https://vibeui.ru/r/checkbox-001.json
Installs to: components/vibeui/checkbox-001.tsx (the exact path follows this project's components.json aliases).
npm dependencies: none.
Registry dependencies: none.

Install it from the registry. Do not recreate it from the description,
do not substitute a similar component from another library, and do not
rewrite it to match the project's existing style.

## 2. What it is
A checkbox whose target is the whole row — label and description included — not a 16px square in the corner. The tick is drawn in CSS; a native input holds the state.

A checkbox as a row: a label, a description under it and a square with a tick. The whole row is the target because the component's root is a <label>. The tick is drawn from two borders and grows from nothing, and a wash appears on hover. A native input inside keeps keyboard and form behaviour free. Zero dependencies, one file, its own palette.

## 3. How to use it
import { Checkbox001 } from "@/components/vibeui/checkbox-001"

<Checkbox001
  name="reports"
  defaultChecked
  label="Email me reports"
  description="Once a week, in a short email."
/>

Read the installed file for the full prop list.

## 4. Where to place it
This is a small inline component. Put it exactly where the user asked,
inside the existing markup. Do not create a new page, section or
wrapper for it. If a similar control already sits in that spot,
replace it instead of adding a second one.

Placement: ___
(The user fills this line in. If it is still blank, ask where to put it
instead of guessing.)

## 5. Keep exactly as installed
- the local --vibeui-checkbox-001-* palette — do not swap it for your theme tokens (bg-primary, border-input, text-muted-foreground and the like)
- the <label> root: it is what makes the entire row clickable, description included
- the native input[type=checkbox] with appearance:none — state, the space key and form submission all rest on it
- the tick made of two borders rotated 45° and its growth from scale(0.4) when checked
- the focus-visible outline on the square: checkboxes get toggled from the keyboard
- the negative margins that offset the row's padding: without them the component sticks out next to the other form fields
- the :has(input:disabled) rules — they dim the whole row rather than just the square
- the <style> block inside the component — it holds the palette, the geometry and the tick animation

## 6. You may change
- the label and description copy; omit description and the row becomes single-line
- the accent through the accent prop — it colours the filled square and the focus ring
- any native input props: name, checked, defaultChecked, onChange, required, disabled, value
- outer spacing and width through className
- stacking: several rows sit together with no wrappers, a gap on the parent is enough

## 7. Rules
- Do not wrap the component in your own <label> — there is one inside, and nested labels break clicking.
- The indeterminate state is not supported: it is a DOM property and cannot be set in markup. If you need a third state, use a different component.
- For a group of checkboxes wrap the rows in a <fieldset> with a <legend>: the row itself carries no group heading.
- Do not lift the CSS variables into globals.css: the component has to stay a single file.

## 8. Verify
- it renders with no console errors;
- it looks like the preview on the VibeUI page you copied this from;
- if it does not, you changed something listed in section 5 — put it back.

For developers

npx shadcn@latest add https://vibeui.ru/r/checkbox-001.json
https://vibeui.ru/r/checkbox-001.json

Компонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-checkbox-001-*. Корень — <label>, поэтому кликается вся строка вместе с пояснением. Внутри нативный input[type=checkbox] с appearance:none: состояние, клавиатура и участие в форме остаются нативными. Галка — две грани квадрата, повёрнутые на 45°, и она вырастает из нуля при отметке; иконочная библиотека не нужна. Отрицательные margin компенсируют внутренние отступы строки, чтобы компонент не сдвигался относительно соседей.

Component source

The same file your agent installs. Here in case you would rather copy it by hand.

import type { ComponentPropsWithoutRef, CSSProperties } from "react"

export type Checkbox001Props = Omit<
  ComponentPropsWithoutRef<"input">,
  "type" | "size"
> & {
  label?: string
  /** Пояснение под подписью. Кликается вместе с ней. */
  description?: string
  accent?: string
}

// Идея компонента: кликабельна вся строка, а не квадратик 16×16. Галка
// рисуется двумя гранями и появляется прочерком времени, а не картинкой:
// иконочная библиотека не нужна, состояние держит нативный input.
const STYLES = `
:where([data-vibeui-block="checkbox-001"]){
--vibeui-checkbox-001-surface:oklch(1 0 0);
--vibeui-checkbox-001-surface-border:oklch(0.91 0.006 265);
--vibeui-checkbox-001-fg:oklch(0.24 0.016 265);
--vibeui-checkbox-001-muted:oklch(0.54 0.014 265);
--vibeui-checkbox-001-bg:oklch(1 0 0);
--vibeui-checkbox-001-border:oklch(0.82 0.01 265);
--vibeui-checkbox-001-accent:oklch(0.55 0.2 262);
--vibeui-checkbox-001-mark:oklch(1 0 0);
--vibeui-checkbox-001-hover:oklch(0.55 0.02 265 / 7%);
--vibeui-checkbox-001-radius:0.625rem;
--vibeui-checkbox-001-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
/* Собственная подложка: подпись и пояснение — это текст, и на тёмной
   странице он обязан читаться без правки палитры проекта. */
[data-vibeui-block="checkbox-001"]{
box-sizing:border-box;padding:0.75rem 0.875rem;
background:var(--vibeui-checkbox-001-surface);
border:1px solid var(--vibeui-checkbox-001-surface-border);border-radius:0.875rem;
display:flex;align-items:flex-start;gap:0.6875rem;
padding:0.625rem 0.75rem;margin:-0.625rem -0.75rem;
border-radius:var(--vibeui-checkbox-001-radius);cursor:pointer;
font-family:var(--vibeui-checkbox-001-font);color:var(--vibeui-checkbox-001-fg);
transition:background-color .16s ease;
}
[data-vibeui-block="checkbox-001"]:hover:not(:has(input:disabled)){background:var(--vibeui-checkbox-001-hover)}
[data-vibeui-block="checkbox-001"]:has(input:disabled){cursor:not-allowed;opacity:.55}
[data-vibeui-block="checkbox-001"] input{
appearance:none;-webkit-appearance:none;
flex:none;margin:0.0625rem 0 0;width:1.125rem;height:1.125rem;
border:1.5px solid var(--vibeui-checkbox-001-border);border-radius:0.375rem;
background:var(--vibeui-checkbox-001-bg);cursor:inherit;
transition:background-color .16s ease,border-color .16s ease;
}
[data-vibeui-block="checkbox-001"] input:checked{
background:var(--vibeui-checkbox-001-accent);
border-color:var(--vibeui-checkbox-001-accent);
}
[data-vibeui-block="checkbox-001"] input:focus-visible{
outline:2px solid var(--vibeui-checkbox-001-accent);outline-offset:2px;
}
[data-vibeui-block="checkbox-001"] [data-part="box"]{position:relative;display:flex;flex:none}
/* Галка — две грани квадрата, повёрнутые на 45°; растёт из нуля при отметке. */
[data-vibeui-block="checkbox-001"] [data-part="mark"]{
position:absolute;left:0.375rem;top:0.1875rem;
width:0.3125rem;height:0.5625rem;pointer-events:none;
border-right:2px solid var(--vibeui-checkbox-001-mark);
border-bottom:2px solid var(--vibeui-checkbox-001-mark);
transform:rotate(45deg) scale(0.4);transform-origin:center;
opacity:0;transition:opacity .14s ease,transform .14s ease;
}
[data-vibeui-block="checkbox-001"] input:checked + [data-part="mark"]{opacity:1;transform:rotate(45deg) scale(1)}
[data-vibeui-block="checkbox-001"] [data-part="text"]{display:flex;flex-direction:column;gap:0.125rem}
[data-vibeui-block="checkbox-001"] [data-part="title"]{font-size:0.9375rem;line-height:1.35}
[data-vibeui-block="checkbox-001"] [data-part="description"]{font-size:0.8125rem;line-height:1.4;color:var(--vibeui-checkbox-001-muted)}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="checkbox-001"] *{animation:none!important;transition:none!important}}
`

/**
 * Чекбокс со строкой-мишенью: подпись, пояснение и галка на чистом CSS.
 * Один файл, ноль зависимостей, собственная палитра.
 */
export function Checkbox001({
  label = "Присылать отчёты",
  description = "Раз в неделю, коротким письмом. Отключается в любой момент.",
  accent,
  className,
  style,
  ...props
}: Checkbox001Props) {
  const palette = {
    ...(accent ? { "--vibeui-checkbox-001-accent": accent } : null),
    ...style,
  } as CSSProperties

  return (
    <>
      <style href="vibeui-checkbox-001" precedence="medium">
        {STYLES}
      </style>
      <label
        data-vibeui-block="checkbox-001"
        className={className}
        style={palette}
      >
        <span data-part="box">
          <input {...props} type="checkbox" />
          <span data-part="mark" aria-hidden="true" />
        </span>
        <span data-part="text">
          <span data-part="title">{label}</span>
          {description ? (
            <span data-part="description">{description}</span>
          ) : null}
        </span>
      </label>
    </>
  )
}