Stimulus MultiSelect

bakivernes

Vernes Pendić

Posted on November 22, 2022

Stimulus MultiSelect

The problem

Every developer had to struggle with choosing the right plugin/package for things that are time consuming or have already been done in ways that suit their needs. Juggling 🤹‍♂️ between a package that is smaller in size or has certain features that we need can be frustrating.

Options

But what happens when there are no packages to choose from? On top of that, what if there is a feature that millions of developers need, but struggle to find answers or make custom solutions for every app they make.

I am, of course, talking about the atrocious implementation of the multiple select feature built into every major browser 😫

Built-in multiple select

Crash

The solution

Since this frustrated my colleagues and me for a long time we decided to make our own implementation and open source it.

Image description

We are not pioneers in this, naturally. There is many a plugin trying to solve the same problem. But what stuck with me when researching is none of them seem to quite scratch the perfectionist itch (now always a good thing 😅). Some of them require big dependencies like vue.js or jQuery, while some of them just lack the features or the ability to be customized.

Stimulus Multiselect

You are going to need stimulus.js as a dependency for this package to work. It is a minimal, easy to understand javascript flavor for handling HTML.

If you are using a js bundler with node_modules support (such as esbuild, rollup.js or Webpack) install the package from npm:

yarn add @wizardhealth/stimulus-multiselect
Enter fullscreen mode Exit fullscreen mode

If you're using importmap-rails, you'll need to pin @wizardhealth/stimulus-multiselect:

./bin/importmap pin @wizardhealth/stimulus-multiselect
Enter fullscreen mode Exit fullscreen mode

Usage

Load your stimulus application as usual and the register the multiselect
controller with it:

import { Application } from '@hotwired/stimulus'
import { Multiselect } from '@wizardhealth/stimulus-multiselect'

const application = Application.start()
application.register('multiselect', Multiselect)
Enter fullscreen mode Exit fullscreen mode

The multiselect has many modes of working. You can fetch data remotely or load a static json collection of items. An example of this static approach:

<div data-controller="multiselect" data-multiselect-items-value='[{ "value": "cuckoo", "text": "Cuckoo 🐦"}, { "value": "macaw", "text": "Macaw 🦜"}, { "value": "rooster", "text": "Rooster 🐓"}]' data-placeholder="Search for birds...">
  <select multiple="multiple" class="multiselect__hidden" data-multiselect-target="hidden" name="form[test_ids][]" id="form_test_ids"></select>
</div>
Enter fullscreen mode Exit fullscreen mode

Let's build an app

We are gonna build a Rails app (since Stimulus is mostly used with Rails) that has a backend of different sports. We are gonna search through these sports with the help of the multiselect and return the results back to show in the dropdown.

The setup

  1. Create a new app rails new multiselect_test
  2. Scaffold Sports so we can search through them rails g scaffold Sport name:string
  3. Migrate it! rails db:migrate
  4. Start up the server rails s and get to creating some sports
    Creating sport

  5. Add the package yarn add @wizardhealth/stimulus-multiselect

The implementation

We are going to use the sports#index page for testing. So we need to make the following changes to the controller and view.

  • We are going to make use of a simple where for the purposes of this example. The index needs to like like this. The parameter that contains the search term from the select input is inside params[:q]
# app/controllers/sports_controller.rb

def index
  @sports = Sport.where("name LIKE ?", "%#{params[:q]}%")

  respond_to do |format|
    format.json
    format.html
  end
end
Enter fullscreen mode Exit fullscreen mode
  • The response that the select needs is JSON. So let's change the json response views that are inside app/views/sports/
# app/views/sports/index.json.jbuilder

json.array! @sports, partial: "sports/sport", as: :sport
Enter fullscreen mode Exit fullscreen mode

The select needs a json that contains the value (usually the id) and the text value (what is shown when selecting)

# app/views/sports/_sport.json.jbuilder

json.value sport.id
json.text sport.name
Enter fullscreen mode Exit fullscreen mode
  • Lastly, we need to put the select HTML somewhere. Let's use the sports/index.html.erb for this
<!-- app/views/sports/index.html.erb -->

<div data-controller="multiselect" data-multiselect-search-url-value="/sports" data-placeholder="Search for sports...">
  <select multiple="multiple" class="multiselect__hidden" data-multiselect-target="hidden" name="sports[]" id="sport_ids"></select>
</div
Enter fullscreen mode Exit fullscreen mode
/* app/assets/stylesheets/application.css */

// The css contents from the file mention above go HERE
Enter fullscreen mode Exit fullscreen mode
  • When going to localhost:3000/sports we should see this

Image description

The end product

Now just search any sport you like:

Image description

Why Stimulus Multiselect ❓

  1. Easy to set up
  2. Lightweight
  3. Good documentation
  4. Lot of options for loading data and handling selected items
  5. Design is customizable (css file is extracted so you can make the select suit your application look)
  6. Accessible
  7. Contributions and issue raising are welcome on our GitHub page

The finish line 🔚

Would love to know what you think. Comment, review the code, try the select and tell us how we can improve 💚

Image description

💖 💪 🙅 🚩
bakivernes
Vernes Pendić

Posted on November 22, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related