Forms✨ Premium

Checkbox Animated

CSS-only checkbox: the indigo-bordered square fills in and a white tick grows in 0.2 s, on top of a real native checkbox that works from the keyboard.

CSSTransformCheckbox

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Forms has 20 effects, including 2 free. Explore the category →

3 usage examples

Building-site checklist on a tablet — Checkbox Animated example 1

① Building-site checklist on a tablet

WhenThe site manager walks through the flat before handover. He taps each checked row: the box fills with orange, the tick appears, the item is struck through and the "3 / 5" counter moves on.
WhyOn a tablet held in one hand, the whole row is the finger's target; the growing tick confirms the gesture even in bright sunlight, with no confirmation dialog.
SettingsFive full-width labels in a single root (root background and height removed). .cbx-box border and fill switched to orange #ea580c. The strike-through and the counter are added by the scene, which listens to the change event.
Filters in a restaurant directory — Checkbox Animated example 2

② Filters in a restaurant directory

WhenIn the left column, the visitor ticks "Open Sundays": the list goes from 4 to 2 restaurants. Each filter is ticked or unticked with one click.
WhyCombinable filters are exactly what a checkbox is for: several choices at once, each one reversible. The small animation shows which filter has just been applied.
SettingsSquare reduced to 20 px (with left:5px; top:1px to re-centre the tick), burgundy #8c2f1f. The cards are filtered by the scene from the checked values.
Consent before joining a hiking club — Checkbox Animated example 3

③ Consent before joining a hiking club

WhenAt the bottom of the form, a single box: "I accept the club rules and the mountain safety charter". Until it is ticked, "Sign up" stays greyed out; from the keyboard, Tab then Space is enough.
WhyThis is the box nobody may miss: the clear tick and the focus ring plainly show it is checked, by finger or keyboard.
SettingsGreen #3f7d4e, text on two lines aligned with the square. The button is enabled by the scene on the change event; in production, also put required on the checkbox.

How it works

The block is a <label class="cbx-check"> holding three things: the real <input type="checkbox">, the drawn square .cbx-box and the text. The real checkbox is made invisible (opacity: 0) but stays exactly under the square, at its size: it receives clicks, focus and the checked state, and the form sends it with its name and value. A click anywhere on the text checks it too, since everything sits in the label.

The drawing follows the native state through the input:checked + .cbx-box selector. The 24 px square, with a 2 px #6366f1 border, takes an indigo fill (0.3 s transition). The tick is the ::after pseudo-element: a 6 × 12 px rectangle with only its right and bottom borders drawn, rotated 45°. At rest it is at scale(0); checked, it goes to scale(1) in 0.2 s: the tick grows from its centre.

No JavaScript. Classes are prefixed cbx- and the .fx-0294-root root (dark background, 300 px tall) is just a display frame: in a real form, remove its min-height and background, and the text then takes your page's colour.

Accessibility

  • Real checkbox: the native element stays in the page (no display:none or visibility:hidden): Tab reaches it, Space checks it, a screen reader announces "checkbox, Accept the terms, not checked".
  • Visible focus: on keyboard focus, a light #a5b4fc ring is drawn around the square (input:focus-visible + .cbx-box).
  • Hit area: the whole row (square + text) can be clicked or tapped, not only the 24 px square.
  • Reduced motion: under prefers-reduced-motion: reduce, the fill and the tick appear without transition.
  • Required: for a box that must be accepted before sending, add required to the input: the browser blocks the send and shows its own message.

Browser compatibility

CSS only: :checked, adjacent sibling selector, pseudo-element and transform. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two independent copies, Tab then Space, touch at 390 px, reduced motion. The focus ring needs :focus-visible (Chrome 86, Firefox 85, Safari 15.4).

Chrome 86+✓ Full (measured)
Firefox 85+✓ Full (measured)
Safari 15.4+✓ Full (measured in WebKit)
Edge 86+✓ Full (Chromium engine)
Mobile iOS 15.4+✓ WebKit engine, not checked on a device
Android Chrome 86+✓ Full (touch measured at 390 px)

Older browsers: the checkbox checks and animates, only the keyboard focus ring is missing.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0294-root">
  <label class="cbx-check">
    <input type="checkbox" name="terms" value="yes">
    <span class="cbx-box" aria-hidden="true"></span>
    <span class="cbx-text">Accept the terms</span>
  </label>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Colour (CSS — border of .cbx-box and fill of input:checked + .cbx-box) #6366f1 Change both to keep the square consistent checked and unchecked.
Square size (CSS — width / height of .cbx-box and of the input) 24px For 20 px, also shift the tick (left / top of ::after) and give the invisible input the same size.
Tick speed (CSS — transition of .cbx-box::after) transform .2s Lengthen to .35s for a more visible tick.
Shape (CSS — border-radius of .cbx-box) 6px 50% gives a round box, 2px a stricter square.
Demo frame (CSS — .fx-0294-root) min-height 300px, #0a0a0f background, white text Remove these three settings to place the checkbox in your form: the text takes the page's colour.
Sent name (HTML — name and value) terms = yes What your server receives when the box is checked; nothing is sent when it is not.

FAQ

Yes. It is only transparent: its checked state, name and value go with the form like a normal checkbox.
The code does not handle it. Set input.indeterminate = true in JavaScript and add an input:indeterminate + .cbx-box rule that draws a dash instead of the tick.
Yes: repeat the <label class="cbx-check"> as many times as needed inside the root; each checkbox keeps its own state.