DEV Community

Cover image for Stimulus MultiSelect
Vernes Pendiฤ‡ for Wizard Health

Posted on

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

Top comments (1)

Collapse
 
melashu profile image
Meshu

Thanks for sharing! I love it!

can you please tell me how can I get the selected value?

in the doc I have seen as I can user multiselect-change but not clear how to user it