Checkbox
A checkbox built on the native input, with a label, a description and an indeterminate state.
'use client';
import { Checkbox } from '@akhatmirzo/ui';
export default function CheckboxBasic() {
return (
<div className="flex flex-col gap-3">
<Checkbox label="Shartlarga roziman" />
<Checkbox label="Meni eslab qol" defaultChecked />
<Checkbox label="Qisman tanlangan" checked="indeterminate" />
</div>
);
}
Import
import { Checkbox } from '@akhatmirzo/ui';When to use
- In forms with a "Save" button — the choice takes effect when the form is submitted. For
settings that apply immediately, use a
Switch. - For several independent choices — notification channels, filters. When only one option can
be picked, use a
RadioGroup. - For consent — "I agree to the terms". If it's mandatory, use
requiredanderroron aField. - Phrase labels positively: "Send notifications", not "Don't send notifications".
Sizes
sm is 16px and md (default) is 20px. Both have an invisible hit area larger than the box.
'use client';
import { Checkbox } from '@akhatmirzo/ui';
export default function CheckboxSizes() {
return (
<div className="flex flex-wrap items-start gap-6">
<Checkbox size="sm" label="Kichik · 16" defaultChecked />
<Checkbox size="md" label="O'rta · 20" defaultChecked />
</div>
);
}
With a description
description appears under the label in smaller, muted text and is linked to the input with
aria-describedby.
'use client';
import { Checkbox } from '@akhatmirzo/ui';
export default function CheckboxDescription() {
return (
<div className="flex max-w-sm flex-col gap-4">
<Checkbox
label="Yangiliklar"
description="Haftasiga bir marta yangi imkoniyatlar haqida xat"
defaultChecked
/>
<Checkbox
size="sm"
label="Qurilmani eslab qolish"
description="30 kun davomida qayta kod so'ralmaydi"
/>
</div>
);
}
Indeterminate
checked="indeterminate" shows a "−". It's typically used on a "select all" box when only some
children are selected. onCheckedChange only reports a boolean — you compute the mixed state
yourself.
'use client';
import { Checkbox, type CheckedState } from '@akhatmirzo/ui';
import { useState } from 'react';
const channels = ['Email', 'SMS', 'Telegram'];
export default function CheckboxSelectAll() {
const [selected, setSelected] = useState<string[]>(['Email']);
const all: CheckedState =
selected.length === channels.length ? true : selected.length > 0 ? 'indeterminate' : false;
return (
<div className="flex flex-col gap-3">
<Checkbox
label="Barcha kanallar"
checked={all}
onCheckedChange={(checked) => setSelected(checked ? channels : [])}
/>
<div className="flex flex-col gap-3 pl-7">
{channels.map((channel) => (
<Checkbox
key={channel}
label={channel}
checked={selected.includes(channel)}
onCheckedChange={(checked) =>
setSelected((s) => (checked ? [...s, channel] : s.filter((c) => c !== channel)))
}
/>
))}
</div>
</div>
);
}
States
disabled dims the box and label and blocks clicks. invalid turns the border red and sets
aria-invalid on the input.
'use client';
import { Checkbox } from '@akhatmirzo/ui';
export default function CheckboxStates() {
return (
<div className="flex flex-wrap items-center gap-6">
<Checkbox label="O'chirilgan" disabled />
<Checkbox label="O'chirilgan, belgilangan" disabled defaultChecked />
<Checkbox label="Xato" invalid />
</div>
);
}
With Field
Field connects the error and hint to the checkbox; when error is set, invalid turns on
automatically. Try checking the box.
Davom etish uchun rozilik kerak
'use client';
import { Checkbox, Field } from '@akhatmirzo/ui';
import { useState } from 'react';
export default function CheckboxWithField() {
const [agree, setAgree] = useState(false);
return (
<div className="max-w-sm">
<Field
label="Foydalanish shartlari"
required
error={agree ? undefined : 'Davom etish uchun rozilik kerak'}
>
<Checkbox label="Shartlar bilan tanishdim" checked={agree} onCheckedChange={setAgree} />
</Field>
</div>
);
}
Props
Checkbox accepts every other <input> attribute (name, value, form, onChange ...), and
ref points to the inner <input>. className goes to the root <label>.
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | 'indeterminate' | — | Controlled value |
defaultChecked | boolean | 'indeterminate' | false | Initial value (uncontrolled) |
onCheckedChange | (checked: boolean) => void | — | Called when the user checks or unchecks the box |
label | ReactNode | — | Text next to the box |
description | ReactNode | — | Hint under the label |
size | 'sm' | 'md' | 'md' | Size: 16 / 20px |
invalid | boolean | — | Error state (automatic inside a Field with an error) |
disabled | boolean | — | Disabled state |
className | string | — | Class for the root <label> |
Data attributes
On the root <label>:
| Attribute | Value |
|---|---|
data-state | checked · unchecked · indeterminate |
data-size | sm · md |
data-disabled | Present when disabled |
data-invalid | Present when invalid |
Accessibility
- Native
<input type="checkbox">— toggles withSpace, submits with the form like any checkbox, and browser validation (required) works. - Clicking the label toggles it too — the whole component is a
<label>. - The mixed state is announced with
aria-checked="mixed". - The focus ring shows only for keyboard focus.
- For a checkbox without a label (say, in a table row), pass
aria-label.