🔥 Oxide UI v0.1.0 — Dark mode only, copy-paste ready. Get started →
Skip to content

Checkbox

<input type="checkbox">

Custom-styled checkboxes built on native <input type="checkbox"> — accessible, keyboard-friendly, and fully styled with Tailwind.

Overview

Preview

Notifications

Basic checkbox

Preview
html
<!-- Unchecked -->
<label class="flex cursor-pointer items-center gap-3 group">
  <span class="relative flex h-4 w-4 shrink-0 items-center justify-center rounded border border-zinc-600 bg-zinc-900 transition-all group-hover:border-zinc-500">
    <input type="checkbox" class="sr-only" />
  </span>
  <span class="text-sm text-zinc-300">Accept terms and conditions</span>
</label>

<!-- Checked -->
<label class="flex cursor-pointer items-center gap-3 group">
  <span class="relative flex h-4 w-4 shrink-0 items-center justify-center rounded border border-[#D40C37] bg-[#D40C37] transition-all">
    <input type="checkbox" checked class="sr-only" />
    <svg class="h-2.5 w-2.5 text-white" viewBox="0 0 10 8" fill="none">
      <path d="M1 4L3.5 6.5L9 1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  </span>
  <span class="text-sm text-zinc-300">Accept terms and conditions</span>
</label>

With Vue reactivity

vue
<script setup>
import { ref } from 'vue'
const checked = ref(false)
</script>

<template>
  <label class="flex cursor-pointer items-center gap-3 group">
    <span
      class="relative flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-all"
      :class="checked ? 'border-[#D40C37] bg-[#D40C37]' : 'border-zinc-600 bg-zinc-900 group-hover:border-zinc-500'"
    >
      <input type="checkbox" v-model="checked" class="sr-only" />
      <svg v-if="checked" class="h-2.5 w-2.5 text-white" viewBox="0 0 10 8" fill="none">
        <path d="M1 4L3.5 6.5L9 1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    </span>
    <span class="text-sm text-zinc-300">{{ checked ? 'Enabled' : 'Disabled' }}</span>
  </label>
</template>

Indeterminate state

Preview
html
<!-- Indeterminate — dash instead of checkmark -->
<span class="relative flex h-4 w-4 shrink-0 items-center justify-center rounded border border-[#D40C37] bg-[#D40C37]">
  <span class="h-0.5 w-2 rounded-full bg-white"></span>
</span>
vue
<!-- Set indeterminate programmatically -->
<script setup>
import { ref, onMounted, watchEffect } from 'vue'
const checkboxRef = ref(null)
const indeterminate = ref(true)

watchEffect(() => {
  if (checkboxRef.value) checkboxRef.value.indeterminate = indeterminate.value
})
</script>

<template>
  <input ref="checkboxRef" type="checkbox" ... />
</template>

Card checkbox group

Preview
html
<!-- Selected card -->
<label class="flex cursor-pointer items-center justify-between rounded-lg border border-[#D40C37]/40 bg-[#D40C37]/5 px-4 py-3">
  <span class="text-sm text-zinc-100">Email</span>
  <span class="relative flex h-4 w-4 items-center justify-center rounded border border-[#D40C37] bg-[#D40C37]">
    <input type="checkbox" checked class="sr-only" />
    <svg class="h-2.5 w-2.5 text-white" viewBox="0 0 10 8" fill="none">
      <path d="M1 4L3.5 6.5L9 1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  </span>
</label>

Disabled

html
<label class="flex items-center gap-3 cursor-not-allowed opacity-40">
  <span class="flex h-4 w-4 shrink-0 items-center justify-center rounded border border-zinc-700 bg-zinc-900">
    <input type="checkbox" disabled class="sr-only" />
  </span>
  <span class="text-sm text-zinc-500">Disabled option</span>
</label>

Accessibility notes

  • Use class="sr-only" on the hidden <input> — never display:none, which removes it from keyboard tab order
  • The visible <span> is purely decorative; the real <input> handles all keyboard/screen reader interaction
  • Always wrap in a <label> so the entire row is clickable and the label text is announced
  • For groups of checkboxes, wrap in <fieldset> with a <legend>

Released under the MIT License.