<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="documentos" 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" value="documentos" placeholder="Search items..." 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></div>FilterBar
Description
Related components
| Used Components | Components where is Used |
|---|---|
| Label |
Usage rules
- ✅ Do
- ❌ Don't
# Simula parâmetros de filtros ativos (como viriam de params em uma table)mock_params = { q: { search: "documentos", status: ["ativo", "pendente"], type: ["documento"], date_from: "2024-01-01", date_to: "2024-12-31" }}render(LooposUi::FilterBar.new( show_filter_buttons: false, show_toggle_switch: false, search_options: { name: "q[search]", value: mock_params.dig(:q, :search), placeholder: "Search items...", event_only: false }, mode: :both)) do |bar| # Renderizar pills baseadas nos filtros ativos if mock_params[:q].present? # Filtro por status if mock_params.dig(:q, :status).present? Array(mock_params.dig(:q, :status)).each do |status| bar.with_filter_pill( text: "Status: #{status.humanize}", state: :active, hasCloseButton: true, data: { action: "click->table-filters#delete", key: "status_#{status}" } ) end end # Filtro por tipo if mock_params.dig(:q, :type).present? Array(mock_params.dig(:q, :type)).each do |type| bar.with_filter_pill( text: "Tipo: #{type.humanize}", state: :active, hasCloseButton: true, data: { action: "click->table-filters#delete", key: "type_#{type}" } ) end end # Filtro de data if mock_params.dig(:q, :date_from).present? || mock_params.dig(:q, :date_to).present? date_text = [ mock_params.dig(:q, :date_from), mock_params.dig(:q, :date_to) ].compact.join(" - ") bar.with_filter_pill( text: "Data: #{date_text}", state: :active, hasCloseButton: true, data: { action: "click->table-filters#delete", key: "date_range" } ) end endendNo 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) %>