Skip to content

Checkbox

Neobrutalist-styled checkbox built on reka-ui's CheckboxRoot primitive, with a check indicator.

Demo

Preview
默认
主要
危险
不确定状态(Minus 图标)
自定义 aria-label

Installation

pnpm dlx brutx-vue@latest add checkbox

Usage

vue
<script setup>
import { ref } from 'vue'
import { Checkbox } from 'brutx-ui-vue'

const checked = ref(false)
</script>

<template>
    <div class="flex items-center gap-3">
        <Checkbox v-model:checked="checked" />
        <span class="text-sm font-bold">Accept terms</span>
    </div>
</template>

Variants

VariantDescription
defaultDefault background, standard foreground
primaryPrimary (coral) background
secondarySecondary (mint) background
accentAccent (yellow) background
dangerDanger (red) background
vue
<template>
    <Checkbox variant="primary" />
</template>

Sizes

SizeDescription
smSmall
defaultDefault
lgLarge

With Label

vue
<script setup>
import { ref } from 'vue'
import { Checkbox, Label } from 'brutx-ui-vue'

const checked = ref(false)
</script>

<template>
    <div class="flex items-center gap-3">
        <Checkbox v-model:checked="checked" id="terms" />
        <Label for="terms">Accept terms and conditions</Label>
    </div>
</template>

Disabled State

vue
<script setup>
import { Checkbox } from 'brutx-ui-vue'
</script>

<template>
    <Checkbox disabled />
</template>

Indeterminate State

Set checked to 'indeterminate' to display the indeterminate state. The indicator shows a Minus icon, commonly used for "partially selected" hierarchical selection scenarios.

Uncontrolled mode supports it too: <Checkbox defaultValue="indeterminate" /> initially renders the Minus icon with aria-checked="mixed". Per reka-ui semantics, clicking switches the state to checked — it does not return to indeterminate automatically.

vue
<script setup>
import { Checkbox } from 'brutx-ui-vue'
</script>

<template>
    <Checkbox :checked="'indeterminate'" />
</template>

Props

PropTypeDefaultDescription
checkedboolean | 'indeterminate'Checked state; omitting it puts the component in uncontrolled mode
defaultValueboolean | 'indeterminate'Initial checked state in uncontrolled mode; only effective while checked is undefined
disabledbooleanfalseWhether disabled
variant'default' | 'primary' | 'secondary' | 'accent' | 'danger''default'Color variant
size'sm' | 'default' | 'lg''default'Size
ariaLabelstringLocale default (checkbox.check)Accessibility label
namestringForm field name; when provided, renders a hidden input submitted with the owning <form> as a name/value pair
valuestring | number | bigint | object | null'on'Value submitted with the form
requiredbooleanfalseNative form required flag, passed through to the hidden input
classstringCustom style class

Controlled vs. uncontrolled: When checked is omitted (or undefined), the component maintains its own internal state and notifies the parent via update:checked; use defaultValue to declare the initial state. Once checked is explicitly provided, the component becomes controlled and the prop is authoritative.

Events

EventPayloadDescription
update:checkedboolean | 'indeterminate'Triggered when checked state changes, supports v-model:checked two-way binding

Accessibility

  • Keyboard: Supports Space key to toggle checked state
  • ARIA attributes: Checkbox provides aria-label via locale by default. Falls back to t('checkbox.check') when not provided. Can be omitted when adjacent visible text already describes the purpose; otherwise, provide a more specific description via ariaLabel
  • Focus management: Uses --brutal-ring token for visible focus ring
vue
<script setup>
import { ref } from 'vue'
import { Checkbox, Label } from 'brutx-ui-vue'

const checked = ref(false)
</script>

<template>
    <div class="flex items-center gap-3">
        <Checkbox v-model:checked="checked" id="marketing" ariaLabel="Receive marketing emails" />
        <Label for="marketing">Receive marketing emails</Label>
    </div>
</template>

Brute force builds.