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:

Feb 25, 2025 - 01:10
 0
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:

 id="tags" name="tags" max_items="5" remove_on_backspace?>
   :for={item <- @tags} name="tags" value={item} animate_duplicate?>
    {item}
    X
  
   id="tags" placeholder="Add a tag" />
   :if={@options != []} id="tags" limit_input_to_options?>
     :for={{value, label} <- @options} value={value} label={label}>
      {label}
    
  

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.