29 CSS Checkboxes19 / 29

Pure CSSMIT licensed

Retro Pixel Checkbox

8-bit nostalgia: a jagged, aliased checkmark built entirely from stacked box-shadow 'pixels' — no image files, no SVG. Snaps in blocky and hard-edged, perfect for game UIs, dev tools with personality and retro landing pages.

Published Updated

Live Demo
Try it

The code

<section class="cb-19" aria-label="Retro pixel checkboxes">
  <div class="cb-19__panel">
    <label class="cb-19__row"><input type="checkbox" class="cb-19__input" checked><span class="cb-19__box" aria-hidden="true"><span class="cb-19__px"></span></span><span class="cb-19__label">INSERT COIN</span></label>
    <label class="cb-19__row"><input type="checkbox" class="cb-19__input"><span class="cb-19__box" aria-hidden="true"><span class="cb-19__px"></span></span><span class="cb-19__label">CONTINUE?</span></label>
    <label class="cb-19__row"><input type="checkbox" class="cb-19__input"><span class="cb-19__box" aria-hidden="true"><span class="cb-19__px"></span></span><span class="cb-19__label">EXTRA LIFE</span></label>
  </div>
</section>
.cb-19,
.cb-19 *,
.cb-19 *::before,
.cb-19 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cb-19 ::selection {
  background: #39ff6a;
  color: #04120a;
}

.cb-19 {
  --accent: #2a2f45;
  --c: #39ff6a;
  --p: 3px;
  font-family: ui-monospace,'Courier New',monospace;
  width: 100%;
  min-height: 100vh;
  padding: 40px 20px;
  background: #12131f;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cb-19__panel {
  width: min(400px,100%);
  background: #1b1d2e;
  border: 2px solid #2f3350;
  padding: 10px 14px;
}

.cb-19__row {
  display: flex;
  align-items: center;
  gap: 16px;
  cursor: pointer;
  padding: 13px 8px;
}

.cb-19__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.cb-19__box {
  position: relative;
  flex: none;
  width: 28px;
  height: 28px;
  background: #0e0f18;
  border: 2px solid #4a5080;
  transition: background .12s steps(2),border-color .12s;
}

.cb-19__px {
  position: absolute;
  left: 5px;
  top: 13px;
  width: var(--p);
  height: var(--p);
  background: transparent;
  opacity: 0;
  transition: opacity .1s steps(2);
}

.cb-19__input:checked ~ .cb-19__box {
  background: var(--accent);
  border-color: var(--c);
}

.cb-19__input:checked ~ .cb-19__box .cb-19__px {
  opacity: 1;
  background: var(--c);
  box-shadow: calc(1*var(--p)) calc(1*var(--p)) 0 var(--c), calc(2*var(--p)) calc(2*var(--p)) 0 var(--c), calc(3*var(--p)) calc(1*var(--p)) 0 var(--c), calc(4*var(--p)) calc(0*var(--p)) 0 var(--c), calc(5*var(--p)) calc(-1*var(--p)) 0 var(--c), calc(6*var(--p)) calc(-2*var(--p)) 0 var(--c);
}

.cb-19__input:focus-visible ~ .cb-19__box {
  outline: 3px solid var(--c);
  outline-offset: 3px;
}

.cb-19__label {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .08em;
  color: #c8ccec;
}

@media (prefers-reduced-motion: reduce) {
  .cb-19__box,
    .cb-19__px {
    transition: none;
  }
}
/* No JavaScript — a stacked box-shadow pixel list draws the check on :checked. */
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Checkboxe from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Retro Pixel Checkbox
Source: https://codefronts.com/components/css-checkboxes/retro-pixel-checkbox/

8-bit nostalgia: a jagged, aliased checkmark built entirely from stacked box-shadow 'pixels' — no image files, no SVG. Snaps in blocky and hard-edged, perfect for game UIs, dev tools with personality and retro landing pages.
## HTML
```html
<section class="cb-19" aria-label="Retro pixel checkboxes">
  <div class="cb-19__panel">
    <label class="cb-19__row"><input type="checkbox" class="cb-19__input" checked><span class="cb-19__box" aria-hidden="true"><span class="cb-19__px"></span></span><span class="cb-19__label">INSERT COIN</span></label>
    <label class="cb-19__row"><input type="checkbox" class="cb-19__input"><span class="cb-19__box" aria-hidden="true"><span class="cb-19__px"></span></span><span class="cb-19__label">CONTINUE?</span></label>
    <label class="cb-19__row"><input type="checkbox" class="cb-19__input"><span class="cb-19__box" aria-hidden="true"><span class="cb-19__px"></span></span><span class="cb-19__label">EXTRA LIFE</span></label>
  </div>
</section>
```
## CSS
```css
.cb-19,
.cb-19 *,
.cb-19 *::before,
.cb-19 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cb-19 ::selection {
  background: #39ff6a;
  color: #04120a;
}

.cb-19 {
  --accent: #2a2f45;
  --c: #39ff6a;
  --p: 3px;
  font-family: ui-monospace,'Courier New',monospace;
  width: 100%;
  min-height: 100vh;
  padding: 40px 20px;
  background: #12131f;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cb-19__panel {
  width: min(400px,100%);
  background: #1b1d2e;
  border: 2px solid #2f3350;
  padding: 10px 14px;
}

.cb-19__row {
  display: flex;
  align-items: center;
  gap: 16px;
  cursor: pointer;
  padding: 13px 8px;
}

.cb-19__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.cb-19__box {
  position: relative;
  flex: none;
  width: 28px;
  height: 28px;
  background: #0e0f18;
  border: 2px solid #4a5080;
  transition: background .12s steps(2),border-color .12s;
}

.cb-19__px {
  position: absolute;
  left: 5px;
  top: 13px;
  width: var(--p);
  height: var(--p);
  background: transparent;
  opacity: 0;
  transition: opacity .1s steps(2);
}

.cb-19__input:checked ~ .cb-19__box {
  background: var(--accent);
  border-color: var(--c);
}

.cb-19__input:checked ~ .cb-19__box .cb-19__px {
  opacity: 1;
  background: var(--c);
  box-shadow: calc(1*var(--p)) calc(1*var(--p)) 0 var(--c), calc(2*var(--p)) calc(2*var(--p)) 0 var(--c), calc(3*var(--p)) calc(1*var(--p)) 0 var(--c), calc(4*var(--p)) calc(0*var(--p)) 0 var(--c), calc(5*var(--p)) calc(-1*var(--p)) 0 var(--c), calc(6*var(--p)) calc(-2*var(--p)) 0 var(--c);
}

.cb-19__input:focus-visible ~ .cb-19__box {
  outline: 3px solid var(--c);
  outline-offset: 3px;
}

.cb-19__label {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .08em;
  color: #c8ccec;
}

@media (prefers-reduced-motion: reduce) {
  .cb-19__box,
    .cb-19__px {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — a stacked box-shadow pixel list draws the check on :checked. */
```

How this works

The check is a single tiny square element the size of one 'pixel'. A long box-shadow list places copies of that square at grid offsets (multiples of the pixel size), spelling out a checkmark shape — the classic pure-CSS pixel-art technique. No blur is used, so every pixel stays crisp and aliased.

On :checked the box fills with the retro accent and the pixel check fades in with opacity (a stepped transition can make it 'appear' rather than smoothly fade). Everything is paint/opacity only — no reflow. The input stays sr-only and focusable, with a chunky :focus-visible outline.

Scaling is done by changing one --p pixel-size variable, which recomputes every shadow offset via calc().

Make it yours

  • Resize the whole mark by editing the --p pixel-size custom property.
  • Recolour pixels + fill via --c and --accent.
  • Redesign the checkmark by editing the box-shadow offset list (each entry is one pixel).
  • Add a stepped transition for a true frame-by-frame reveal.

Gotchas — read before shipping

  • Never blur the shadows — blur destroys the pixel aesthetic; keep the spread/blur at 0.
  • All offsets are multiples of --p; change the variable, not each value, to rescale.
  • Keep the fill colour as a state cue so the pixel check isn't the only signal.

Browser support

ChromeSafariFirefoxEdge
49+10+52+49+

Stacked box-shadow pixel art is universally supported.

Techniques used in this demo

Search CodeFronts

Loading…