<div class="lui-filter_bar" data-controller="lui--filter-buttons lui--filter-toggle lui--filter-pills"> <div class="lui-filter_bar__top"> <div class="lui-filter_bar__search"> <div data-controller="search" id="looposui-inputs-search_q_search__5793709857" class="lui-search" data-search-input-outlet="#looposui-inputs-search_q_search__5793709857 .lui-inner-input" data-search-event-only-value="false" > <div data-controller="input" data-input-open-actions-value="false" class="lui-inner-input relative flex gap-2" data-input-original-input-value="" data-input-mode-value="autosubmit" data-input-form-value=""> <div class="w-full flex flex-col"> <span class="lui-input "> <span class="lui-input__addon-left"> <div class="text-[12px] flex items-center text-center"> <i class="fa-regular fa-magnifying-glass text-gray-400"></i> </div> </span> <input name="q[search]" type="search" placeholder="Search..." class="lui-input__input" mode="autosubmit" contentEditable="true" data-input-target="input" data-action="input->search#toggleClearButton input->input#setEditing input->search#onInput change->search#onInput" data-search-target="input"> <span class="lui-input__addon-right"> <span class="flex"> <i class="fa-regular fa-xmark cursor-pointer text-gray-400" data-search-target="clearButton" data-action="click->search#clear click->input#finishEditing"> </i> </span> </span> <span class="lui-input__spinner"> <i class="fa-regular fa-spinner"></i> </span> </span> </div> <span class="lui-inner-input__actions opacity-0 flex items-center gap-1 h-fit" data-input-target="actions"> <button class="lui-button lui-button--icon-only lui-button--neutral--secondary lui-button--size-tiny w-fit w-fit relative" data-controller="lui--button" data-input-target="cancel" data-action="click->input#handleClose" type="button" disabled="disabled"> <div class="opacity-100 inline-flex" data-lui--button-target="leadingIcon"> <div class="flex items-center justify-center" style="width: 12px; height: 12px;"><i class="lui-button__icon lui-button__icon--tiny fa-regular fa-xmark" data-lui--button-target="leadingIcon"></i></div> </div> <div class="absolute w-full flex items-center justify-center opacity-0" data-lui--button-target="loadingIcon"> <i class="lui-m_icon animate-spin material-symbols-outlined" style="--lui-micon-size: 12px;"> progress_activity </i> </div> </button> <button class="lui-button lui-button--icon-only lui-button--neutral--secondary lui-button--size-tiny w-fit w-fit relative" data-controller="lui--button" data-input-target="submit" data-action="click->input#setLoading" type="submit" disabled="disabled"> <div class="opacity-100 inline-flex" data-lui--button-target="leadingIcon"> <div class="flex items-center justify-center" style="width: 12px; height: 12px;"><i class="lui-button__icon lui-button__icon--tiny fa-regular fa-check" data-lui--button-target="leadingIcon"></i></div> </div> <div class="absolute w-full flex items-center justify-center opacity-0" data-lui--button-target="loadingIcon"> <i class="lui-m_icon animate-spin material-symbols-outlined" style="--lui-micon-size: 12px;"> progress_activity </i> </div> </button> </span> </div> </div> </div> <div class="lui-filter_bar__actions"> <div class="lui-filter_bar__button"> <button class="lui-filter_button lui-filter_button--medium lui-filter_button--enabled" data-controller="lui--filter-button" type="button"> <i class="lui-m_icon material-symbols-outlined" style="--lui-micon-size: 16px;"> info </i> <span class="lui-filter_button__text"> Issues </span> <span class="lui-counter lui-counter--tinny" style="color: #ffffff; background-color: #c81720;"> <span class="lui-counter__text">3</span> </span> </button> <button class="lui-filter_button lui-filter_button--medium lui-filter_button--enabled" data-controller="lui--filter-button" type="button"> <i class="lui-m_icon material-symbols-outlined" style="--lui-micon-size: 16px;"> group </i> <span class="lui-filter_button__text"> Operator actions </span> <span class="lui-counter lui-counter--tinny" style="color: #ffffff; background-color: #df8620;"> <span class="lui-counter__text">35</span> </span> </button> <button class="lui-filter_button lui-filter_button--medium lui-filter_button--enabled lui-filter_button--isselected" data-controller="lui--filter-button" type="button"> <i class="lui-m_icon material-symbols-outlined" style="--lui-micon-size: 16px;"> chat_bubble </i> <span class="lui-filter_button__text"> Messages </span> <span class="lui-counter lui-counter--tinny" style="color: #212529; background-color: #F8F9FA; border: var(--Spacings-0, 1px) solid var(--General-Gray-500, #C4CAD0);"> <span class="lui-counter__text">10</span> </span> </button> </div> <div class="lui-filter_bar__toggle"> <div class="flex items-center gap-2 flex-row" data-controller="toggle"> <p class="text-black text-primary-xs-regular"> Only items in Handling </p> <label class="lui-toggle relative"> <input name="only_in_handling" type="checkbox" data-toggle-target="input" data-action=" " data-method="patch" data-turbo_frame="" > <span class="lui-slider" style=""> <span class="lui-toggle__spinner" data-toggle-target="spinner"> <i class="absolute origin-center animate-spin text-[9px] top-px left-px fa-solid fa-spinner"></i> </span> </span> </label> </div> </div> </div> </div></div>FilterBar
Description
Related components
| Used Components | Components where is Used |
|---|---|
| Label |
Usage rules
- ✅ Do
- ❌ Don't
render(LooposUi::FilterBar.new( show_filter_buttons: true, show_toggle_switch: true, buttons: [ { text: "Issues", showLeftIcon: true, left_icon: "info", showCounter: true, count: 3, counter_kind: :danger }, { text: "Operator actions", showLeftIcon: true, left_icon: "group", showCounter: true, count: 35, counter_kind: :warning }, { text: "Messages", showLeftIcon: true, left_icon: "chat_bubble", showCounter: true, count: 10, isSelected: true }, ], search_options: { name: "q[search]", placeholder: "Search...", event_only: false }, toggle_options: { label: "Only items in Handling", name: "only_in_handling", checked: false }, mode: :both)) do |bar| bar.with_filter_pill( text: "Status: Ativo", state: :active, hasCloseButton: true ) bar.with_filter_pill( text: "Tipo: Documento", state: :enabled, hasCloseButton: true ) bar.with_filter_pill( text: "Data: Hoje", state: :enabled, hasCloseButton: true )endNo notes provided.
No params configured.
Description
The FilterBar component is a comprehensive filtering interface that combines search functionality, filter buttons, toggle switches, and filter pills into a unified component. It's designed to work seamlessly with tables and provides dynamic filter management through JavaScript events.
Arguments
| Property | Default | Required | Description |
|---|---|---|---|
buttons |
[] |
- | Array of filter button configurations. Each item is a hash with properties for LooposUi::FilterButton |
show_search |
false |
- | Controls visibility of the search input field |
show_filter_buttons |
false |
- | Controls visibility of filter buttons |
show_toggle_switch |
false |
- | Controls visibility of the toggle switch |
search_options |
{} |
- | Hash of options to pass to the LooposUi::Inputs::Search component |
toggle_options |
{} |
- | Hash of options to pass to the LooposUi::Toggle component (excluding label, which is handled separately) |
mode |
:both |
- | Layout mode: :both (header + pills), :header (header only), or :pills (pills only) |
table_id |
nil |
- | Optional table ID for integration with table components |
Layout Modes
:both- Displays both the header (search + buttons + toggle) and the pills section:header- Shows only the header section (first row):pills- Shows only the pills section (second row)
Buttons Configuration
The buttons option accepts an array of hashes, where each hash contains properties for LooposUi::FilterButton:
buttons: [ { text: "Issues", showLeftIcon: true, left_icon: "info", showCounter: true, count: 3, counter_kind: :danger }, { text: "Operator actions", showLeftIcon: true, left_icon: "group", showCounter: true, count: 35, counter_kind: :warning }]Search Options
The search_options hash is passed directly to the LooposUi::Inputs::Search component:
search_options: { name: "q[search]", placeholder: "Search...", event_only: false}Toggle Options
The toggle_options hash is passed to the LooposUi::Toggle component, except for label which is handled separately by the FilterBar:
toggle_options: { label: "Show inactive items", name: "show_inactive", checked: false}Slots
filter_pills
Renders multiple LooposUi::FilterPill components. Each pill represents an active filter:
<%= render LooposUi::FilterBar.new(...) do |bar| %> <% bar.with_filter_pill( text: "Status: Active", state: :active, hasCloseButton: true ) %> <% bar.with_filter_pill( text: "Type: Document", state: :enabled, hasCloseButton: true ) %><% end %>Controller Targets
| Target | Description |
|---|---|
pillsContainer |
Container element for filter pills |
pill |
Individual filter pill elements |
clearAllButton |
Button to clear all filters |
Controller Values
| Value | Type | Description |
|---|---|---|
tableId |
String | ID of the associated table element |
Controller Methods
| Method | Description |
|---|---|
handleFiltersShow |
Handles the filters:show event to dynamically add filter pills |
handleFiltersDelete |
Handles the filters:delete event to remove specific filter pills |
handleFiltersClearAll |
Handles the filters:clearAll event to remove all filter pills |
clearAll |
Clears all filters and dispatches the filters:clearAll event |
addPill |
Dynamically adds a new filter pill based on a filter key |
removePill |
Removes a filter pill and dispatches the filters:delete event |
handleToggleChange |
Handles toggle switch changes and dispatches filter:toggle events |
handleButtonClick |
Handles filter button clicks and manages button selection state |
syncButtonStates |
Synchronizes filter button states based on form inputs |
syncToggleStates |
Synchronizes toggle switch state based on URL parameters and form data |
JavaScript Events
The FilterBar controller listens to and dispatches several custom events:
Listened Events
| Event Name | Description |
|---|---|
filters:show |
Adds filter pills dynamically. Event detail should contain toShow array |
filters:delete |
Removes a specific filter pill. Event detail should contain toDelete key |
filters:clearAll |
Removes all filter pills |
filter:toggle |
Handles filter toggle changes (from buttons or toggle switches) |
Dispatched Events
| Event Name | Description |
|---|---|
filters:clearAll |
Dispatched when the "Clear all filters" button is clicked |
filters:delete |
Dispatched when a filter pill is removed |
filter:toggle |
Dispatched when a filter button or toggle switch changes state |
Event Details
filters:show Event
const event = new CustomEvent('filters:show', { detail: { toShow: ['status$active', 'type$document'], tableId: 'table_123', // optional }, bubbles: true,})document.dispatchEvent(event)filters:delete Event
const event = new CustomEvent('filters:delete', { detail: { toDelete: 'status$active', tableId: 'table_123', // optional }, bubbles: true,})document.dispatchEvent(event)filter:toggle Event
const event = new CustomEvent('filter:toggle', { detail: { name: 'show_inactive', value: true, tableId: 'table_123', // optional }, bubbles: true,})document.dispatchEvent(event)Integration with Tables
When table_id is provided, the FilterBar automatically integrates with table components:
- The controller finds the table element by ID
- Filter pills are dynamically added/removed based on table filter events
- Button and toggle states are synchronized with form inputs
- The "Clear all filters" button visibility is managed automatically
Usage Examples
Basic Filter Bar with Search
<%= render LooposUi::FilterBar.new( show_search: true, search_options: { name: "q[search]", placeholder: "Search items...", event_only: false }, mode: :both) do |bar| %> <% bar.with_filter_pill(text: "Status: Active", state: :active) %><% end %>Filter Bar with Buttons and Toggle
<%= render LooposUi::FilterBar.new( show_search: true, show_filter_buttons: true, show_toggle_switch: true, buttons: [ { text: "Issues", showCounter: true, count: 3 }, { text: "Messages", showCounter: true, count: 10 } ], search_options: { name: "q[search]", placeholder: "Search...", event_only: false }, toggle_options: { label: "Show inactive items", name: "show_inactive", checked: false }, mode: :both) do |bar| %> <% bar.with_filter_pill(text: "Status: Active", state: :active) %><% end %>Header Only Mode
<%= render LooposUi::FilterBar.new( show_search: true, show_filter_buttons: true, search_options: { name: "q[search]", placeholder: "Search...", event_only: false }, mode: :header) %>Pills Only Mode
<%= render LooposUi::FilterBar.new( mode: :pills) do |bar| %> <% bar.with_filter_pill(text: "Status: Active", state: :active) %> <% bar.with_filter_pill(text: "Type: Document", state: :enabled) %><% end %>Integration with Table
<%= render LooposUi::FilterBar.new( table_id: "table_items", show_search: true, show_filter_buttons: true, search_options: { name: "q[search]", placeholder: "Search...", event_only: false }, mode: :both) %>