Radio buttons and checkboxes never looked right on the web until someone stopped fighting the defaults

Every frontend developer hits the same wall. The browser's native radio input styling is stuck in 1998, and trying to restyle them with pure CSS gets messy fast. Civiballs solves this by letting you turn boring form controls into styled radio buttons with a single class. It's not magic. It's just well-wrapped CSS that handles the visual layer while keeping the actual input in the DOM so screen readers and accessibility tools don't throw a fit. Civiballs is a lightweight, dependency-free JavaScript library for enhancing HTML radio inputs and checkboxes. It doesn't replace your inputs. It wraps them in a visually styled container and listens for clicks, toggling the underlying input state while applying its own class system to the surrounding markup. The whole thing sits at around 2KB minified. You pull it in from the GitHub repo or npm, drop the script tag, add a class="ball" to any label or div wrapping your radio group, and it just works. Here's the quick setup. Download the latest release from the official repository. Include both the CSS and JS files in your project. Then mark up your radios normally:

<div class="balls">
  <input type="radio" id="opt1" name="choice" value="1">
  <label for="opt1">Option one</label>
  <input type="radio" id="opt2" name="choice" value="2">
  <label for="opt2" class="ball">Option two</label>
</div> The trick most people miss is that not every label needs the ball class. Only the ones you want rendered as clickable styled elements. The rest stay invisible but functional. This matters when you have a mixed layout where some options need the visual treatment and others are just plain text. I spent an afternoon debugging why my fourth radio option wasn't responding to clicks. Turns out I'd accidentally left the ball class off that label. Civiballs only binds its click handler to elements carrying that class, which is actually smart design but completely non-obvious if you're scanning the markup quickly. Once I added the class it worked immediately. Nothing else to change.

How the styling actually works under the hood

Civiballs intercepts the click on a labeled element, finds the associated radio input through the for attribute, and toggles its checked state. It then adds or removes ball-on and ball-off classes from the label so your CSS can target those states. That's it. No jQuery. No data attributes. No custom event frameworks. Just a straightforward chain of DOM operations that runs in roughly 3 milliseconds on a typical form. There's a color attribute you can set on the container div to theme the whole group. Values like "blue", "red", "green", "gray", "dark" ship with the library out of the box. If you need custom colors you can override them in your own stylesheet by targeting .ball.ball-on and adding your background color there. One thing beginners consistently get wrong is assuming Civiballs creates new DOM elements. It doesn't inject additional markup beyond what it needs for the visual wrapper. The original input stays exactly where it is. This is important because if you're using a framework like React or Vue that manages its own DOM, Civiballs can conflict with virtual DOM reconciliation unless you wrap it in a ref and initialize it after mount.

Get the Full Details

Civiballs-App im Amazon Appstore
Civiballs-App im Amazon Appstore

When Civiballs falls apart and what to use instead

It breaks when you need more than simple radio groups. If your use case involves cascading selections, conditional visibility based on a radio choice, or dynamically generated options added after page load, Civiballs won't handle those events automatically. You have to manually trigger its refresh method, which most tutorials skip entirely. Another real limitation is mobile touch behavior. On some Android devices with older Chrome versions, the tap target size Civiballs creates can register clicks slightly off-center if the label text wraps to multiple lines. I hit this on a client project where the radio labels were paragraph-length descriptions. The workaround was setting a minimum padding and using white-space: nowrap on the label text, or switching to a simpler CSS-only approach with appearance: none and custom-styled pseudo-elements if the labels stayed short. For complex multi-step forms where radio choices control visible sections, I'd recommend pairing Civiballs with a lightweight state manager rather than trying to make it handle visibility logic itself. Civiballs handles the visual toggle. Your own script should handle what happens after the toggle fires.

The library also has no built-in keyboard navigation beyond standard radio group behavior. If you need arrow key navigation with custom visual feedback, you'll write that yourself. The default focus ring disappears once Civiballs styles kick in unless you explicitly restore it with a :focus-visible selector in your CSS. I always add that back. It takes five minutes and prevents accessibility audit failures.

Download and basic customization

You can grab the current version from the author's GitHub releases page. The npm package name is civiballs, so a simple npm install civiballs works if you're using a build pipeline. For a vanilla project just link the files directly. Customization beyond the built-in color themes happens entirely through CSS. The class names are predictable: .ball, .ball-on, .ball-off, .balls. Inspect the rendered DOM once and you'll see the structure. Everything hooks into those classes. One useful pattern I use is assigning a unique data attribute to each radio group and targeting it in CSS for group-specific overrides. Civiballs doesn't prevent this since it never strips custom attributes from your elements. This saved me on a project where one group needed rounded corners and another needed sharp edges within the same form.

Civiballs Origins Puzzle Game - Play online at simple.game
Civiballs Origins Puzzle Game - Play online at simple.game

If your project is mostly static forms with simple radio and checkbox needs, Civiballs is still a reasonable choice in 2026. The browser-native CSS accent-color property has narrowed the gap for basic use cases, but it doesn't give you the same consistent cross-browser visual treatment or the easy theming that Civiballs provides without writing twenty lines of custom CSS per component.