What's the best way to manage checked state with custom checkboxes?

I’m developing a multiselect feature, and came to the conclusion that it should be implemented as styled divs that tracks their selected state in a hidden checkbox as in this example. The thing is my divs are styled differently based on the checked status.

What is the best way to update this checked state in a way that the styling of the div also changes? So far I’ve thought of two options:

  1. Use a live component for every item and use click events to update the styling and checkbox state. This seems like a poor option because there could be dozens or more shown on the page at any time.
  2. Use AlpineJS, although updating the styling might be a pain plus adds Alpine weirdness and another dependency to the project.

Neither seem like a good option, what are your thoughts? This is what I want to implement:

1 Like

Plain CSS? Also I would rather suggest using label instead of div as this way you don’t have to add any hooks, JavaScript code or phoenix events.

Helpful resources

You should be adding a label and a input pair and all the event handling will be done for you. use plain css or if using tailwind, there are utility classes for checked state as well as group, peer and has selectors which you can use to handle the UI.

What you’re looking for is a classic CSS trick called a “checkbox hack”. Search that for endless examples. Here’s a good one:

One thing to be careful of is that hiding the checkbox makes the form inaccessible (it can’t be tabbed to). You can fix this by positioning the real checkbox offscreen (position: fixed; top: -9999px;, etc) and then styling the visible fake checkbox with an outline when the real (off-screen) checkbox is focused. I mention this because, strangely, I’ve never seen it mentioned anywhere else (though I strongly doubt I am the first person to think of it).

1 Like