trisolaran

trisolaran

LiveSelect - Dynamic selection input component for LiveView

Hi! :waving_hand:

I would like to present LiveSelect, a little library that I wrote to easily add a dynamic selection input to your LV forms.

The idea is that the user can type some text, and the component presents a dropdown with content that is filled dynamically by your LV as the user types (LiveSelect sends your LV a message, and your LV replies with the new list of options). The user can then select an option or continue the search.

demo

Background

There are a few (mostly oldish) tutorials that explain how to build similar components, but to the best of my knowledge no component you can add to your LV as a library and just use.

While creating this component for one of my projects, I put considerable effort trying to get it right, especially handling all the tiny little details like navigation with the arrow keys, selection with mouse or enter key, resetting the selection and so on. Therefore, I decided to make it all available as an easy-to-use library so that hopefully the next poor developer won’t have to reeinvent this wheel :wink:

How to use

To use LiveSelect, you add it to your mix dependencies, import the JS hooks (1-2 lines) into your app.js, and add an extra line in your tailwind configurations. You’re now ready to add the LiveSelect input to your forms.

I would be very happy if at least some folks found this component useful, and I’ll be extremely grateful for any feedback :folded_hands:

Thanks,
Max

Hexdocs

https://github.com/maxmarcon/live_select

First 10 of 107 Posts Switch mode

zachallaun

zachallaun

This looks great! Thanks for releasing it.

Do you have any plans/thoughts about exposing it as a component when LiveView 0.18 hits? Link to new attr syntax (not sure if there’s better docs available as of now).

TwistingTwists

TwistingTwists

ivanminutillo

ivanminutillo

This is so great, I was hoping for such effort since a while now.
Does it handle multiselect already, or anyway you plan to implement it?

trisolaran

trisolaran OP

Thanks @zachallaun !

Interesting, I haven’t been following the development of the 0.18 version that much to be honest, so thank you for the pointer. Looks like LV will soon incorporate some features reminiscent of Surface. I was expecting that and I find it good :+1:

To answer your question: my initial idea was to provide an interface as similar as possible to Phoenix.HTML.Forms, because I beleive this is how most people write LV forms:

<%= live_select form, field, options %>

However, as I mentioned, I would like to make the rendering of the options in the dropdown customizable. The most natural way to do that seems to be using slots, and so I believe I’m gonna have to provide a second interface that uses function components. Let’s say you wanna display all the option labels in uppercase (silly example but just to make the point):

<.live_select form={form} field={field} options={options} let={{label, _value}}>
  <div><%= String.upcase(label) %></div>
</.live_select>

So the answer to your question is: “probably yes”.

I’m interested in any thoughts you might have

trisolaran

trisolaran OP

Hi @TwistingTwists and thanks.

The LiveSelect component renders 2 inputs: a visible one where the user enter text and that will contain the label of the option after selection, and a hidden one that will contain the actual value of the option after selection.

Let’s say you do this in your form:

<%= live_select form, :user_role %>

This will render 2 inputs: a visible text input called :user_role_text_input and a hidden one called :user_role

If now you pass the options: %{user: 1, admin: 2, guest: 3}, LiveSelect will render 3 labels in the dropdown: ["user", "admin", "guest"]. If you select one of them, the corresponding numeric value (1, 2 or 3) will be the value of the hidden input :user_role, whereas the selected option label (“user”, “admin” or “guest”) will be the value of the text input :user_role_text_input.

The label and the values of the options could also be the same of course (i.e. options = ["user", "admin", "guest"]), in which case both :user_role and :user_role_text_input will have the same value.

Hope this makes sense

trisolaran

trisolaran OP

Hi @ivanminutillo and thank you!

you raise a very good point, and I confess I had not given this too much thought until I read your question :slight_smile:

I think that a good way to handle multiple selects is to do what this jQuery library is doing:

Basically adding removable tags to the input field as the user selects options.

What do you think?

TwistingTwists

TwistingTwists

Right on this makes sense.

I’ve had very contrived examples of trying to do the same in Angular in past. This approach is relatively breeze.

Thanks for explaining this one!

milangupta

milangupta

This is awesome !! Thank you.
A couple of suggestions if I may ..

  1. commenting out the phx-change on the component (component.html.heex) allows for the event to fire. For some reason, I was not seeing the handle_event triggering (only the handle_info callback).
  2. a bit of a hack, but I needed to have three LiveSelect components on the same form with “intelligence” i.e. the search criteria and the options displayed were interdependent. Hence, I needed the values of all three components passed into handle_info (for determining the options to display) when any of them changed. This is similar to the “grouping” function of checkboxes and how the values are passed into liveview callbacks. I was able to accomplish this with a few tweaks .. basically, am using the handle_event to collect the key value pairs as all form component values are passed to handle_event upon change. I then pass this back as an assign and onto the LiveSelect component (had to add a “values” attribute in ChangeMsg) which then shows up nicely in the handle_info callback. I can submit the PR on github if you think worthy ..
  3. One side-effect, for handle_events to be generated reliably, I had to also remove the debounce (handle-info always fires).
  4. Do you think it is possible to adapt this so it can work within a live_component ? I am still learning ..

Again, thank you.

trisolaran

trisolaran OP

Thank you @milangupta this is excellent feedback! I’m currently traveling and unable to answer. Expect a proper response over the weekend :+1:

milangupta

milangupta

So as I dug deeper into the design, I realized I didn’t need to use handle_event triggered by phx-change at all, so 1 & 3 are not needed. The “grouping” equivalent can be accomplished over the top. Your widget is quite elegant and carefully designed. There is a lot of work that has gone in to make it behave precisely ..

The one thing I struggled with is the interface/integration with the parent - I had to implement a new message to be able to get the “selection” event in the parent. I did not see a way for the parent to determine whether selections had been made.

For complex/tightly integrated interactions, is there an easier way to be able to get to the state of the component i.e. directly accessing variables ?

Where Next?

Trending in Announcing Top

bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
387 14960 120
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

Other Trending Topics Top

type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
bjorng
We want to introduce a new native datatype to Erlang: native records. Although replacing all tuple records with native records is not our...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New

We're in Beta

About us Mission Statement