Customising Ember Power Select

Chris Game
6 min readMar 23, 2018

--

Whether you use EPS in your app already or you are yet to experience this wonderful add-on, it may come as a surprise to you how much it can be customised. The whole component can be restyled and—to a certain extent the behaviour—can be changed.

To give you an idea of what I mean, here is an example of a component I built recently at Kayako.

It’s based on EPS and uses the navigable pattern that is described in the cookbook section of the docs. In addition to that it uses a custom trigger to allow search functionality and custom options to allow the navigation shown on the second level to remain fixed whilst the other options scroll. You can also see in the demo above that there is an option to toggle a filter on the list.

Specifying your own trigger and option is done like this

The trigger is rendered without any surrounding markup.

The options are rendered inside the default unordered list tag but you have access to the markup that is used around each option.

Having access to the <li> tag is the difference between specifying a replacement options component and yielding.

When you use EPS in it’s block form, what you have in the block is rendered for each option with EPS handling the rendering of the surrounding <li> . Normally this is great, saves you some work and hides the complexity you don’t need to see. But sometimes you need access to modify the <li> tag it’s self, this is when you should opt for a custom options component.

Generally when overriding either of these areas some of the default behaviour is still required and additions are then made to it. To restore all the default behaviour you can simply find the trigger and options components inside the EPS source and extend yours from them. The original trigger and options templates can then be copied. EPS works across a number of browsers and devices, it also supports a lot of features. If you don’t need all of the features and functionality then just take what you need from the default implementation and apply it to the components you are using to override the default trigger and options.

The behaviour i added to the trigger in this example was to allow it to capture a search query. This state is only shown when the dropdown is open, if the dropdown is closed the selected item is displayed as per the standard trigger. I needed to make a slight adjustment over the standard trigger as the selected option has a parent so I want to show the parent and the option selected when the dropdown is closed. This is as simple as adding the clause to the components template highlighted below.

The action that is triggered by the oninput event of the input element filters the list of available parent levels and then filters their options for any matches. If some are found a fake option is added to the start of the list of matched options. It has the same attributes defined as a real parent level with the addition of a disabled property that is set to true. This means no additional styling is needed. See the example below for details…

I also modified the options behaviour so that the back navigation and parent level are fixed with the rest of the options being scrollable. That meant i needed to target these options specifically. Again I did this by adding some fake options objects.

In the navigable select example in the cookbook the transformed options computed property is where most of the magic happens. In it’s standard form it looks like this…

You can see a fake option is already added that contains the parent level. I took this a stage further by adding the navigation option, a divider and the level name in a similar way. This has the benefit of these additional options still being navigable by the arrow keys and selected with enter or space. The divider is disabled so it’s not selectable and is skipped over when you use the arrow keys to move through the options. This is all default behaviour courtesy of EPS because as far as it is concerned these are just standard options. If i had simply added these as buttons in the template all of this behaviour would have been lost.

After the modifications it ended up looking like this…

I then check for these attributes in the options component to be able to apply css only to the special options. The highlighted section below is all i added over the standard EPS options component.

You may also have noticed that the width of the options area expands beyond the width of the trigger when it’s content requires it. This is done by setting matchTriggerWidth=false on the EPS component. This will then be applied to the options, even if you are using a custom options component.

So that is all it took. The feature to toggle a filter on the options was pretty straight forward too. It followed the same pattern as above, adding a fake option with a unique attribute so it could be targeted. In this example the filter state does not reset if you navigate out of the level of options you are on or close the dropdown. The filter state is also applied on a per level basis and some other logic is employed to make sure if there are less than three options available for a particular filter state the option to filter is not shown and the filter is not applied.

Conclusion

Hopefully this has given you a few ideas about how to build components in your applications or maybe made ember-power-select a strong contender to use as the basis for your controls. You can find more details on the philosophy behind EPS in the architecture docs and the API docs cover all the options you have available to you in detail.

If you think you want to build on top of something more basic than ember-power-select check out ember-basic-dropdown!

--

--