DEV Community

Cover image for Building an Interactive Tag Input Component with Phoenix LiveView
Mykolas Mankevicius
Mykolas Mankevicius

Posted on

Building an Interactive Tag Input Component with Phoenix LiveView

I've been exploring ways to create reusable UI components with Elixir and Phoenix LiveView. Here's my latest creation: a flexible, interactive tag input component that combines server-side rendering with client-side interactivity using LiveView Hooks.

What We're Building

The tag input component allows users to:

  • Add items by typing and pressing Enter or Tab
  • Remove items with a button or backspace (when enabled)
  • Enforce a maximum item limit
  • Detect and animate duplicate entries
  • Provide autocomplete suggestions (optional)
  • Submit items as part of a form

Here's a quick demo of what it looks like:

<List.root id="tags" name="tags" max_items="5" remove_on_backspace?>
  <List.item :for={item <- @tags} name="tags" value={item} animate_duplicate?>
    <span>{item}</span>
    <List.item_remove>X</List.item_remove>
  </List.item>
  <List.input id="tags" placeholder="Add a tag" />
  <List.options :if={@options != []} id="tags" limit_input_to_options?>
    <List.option :for={{value, label} <- @options} value={value} label={label}>
      {label}
    </List.option>
  </List.options>
</List.root>
Enter fullscreen mode Exit fullscreen mode

The Architecture

This component is split into three main parts:

  1. Elixir Components: Phoenix components for server-side rendering and form integration
  2. JavaScript Hooks: LiveView Hooks for client-side interactivity
  3. CSS: TailwindCSS classes for styling (customizable)

Server-Side: Elixir Components

The Elixir side uses two main modules:

  • ListInputUI.Headless.List: Defines the core list structure with components like root, item, input, and options these component don't assume anything about your styles
  • ListInputUI.Field: Provides a form-aware wrapper with labels, error handling and styling

Client-Side: LiveView Hooks

Two JavaScript hooks power the interactivity:

  1. ListInputHook:

    • Manages the core list functionality
    • Adds/removes items
    • Enforces max items and duplicate detection
    • Triggers change events for LiveView updates
  2. ListInputOptionsHook:

    • Manages the autocomplete dropdown
    • Filters options based on input
    • Handles keyboard navigation (Arrow keys, Enter)
    • Highlights matching text using CSS Highlights API

Integration with LiveView

The hooks integrate seamlessly with LiveView by:

  • Attaching to DOM elements via phx-hook
  • Dispatching change events that trigger LiveView form updates
  • Using hidden inputs to submit data with forms

Next Steps

I plan to enhance this component by:

  • Improving accessibility with ARIA attributes
  • Show examples for searchable options in dropdown from the server
  • Create a video of how i've done this.

You can find the full source code on @Gumroad, don't worry it's free if you choose so.

Top comments (0)