Overview & Philosophy
ln-filter is applied to a filter control via <nav data-ln-filter="targetId"> containing standard checkbox inputs (data-ln-filter-value="...") and an "All" reset sentinel (data-ln-filter-reset). On checkbox change events, it updates active filter criteria and maintains sentinel synchronization automatically. It evaluates target items or table rows by dataset attributes or column text, applies data-ln-filter-hide and .hidden to non-matching elements, and dispatches cancelable ln-filter:change CustomEvents for active coordinators to claim.
In ln-ashlar, this zero-dependency primitive operates as an event-driven layer upgrading standard HTML checkboxes into reactive multi-column and list filter controls.
The Filter Primitive Doctrine
A filter primitive does not maintain a virtual state cache or coordinate remote databases. It uses native HTML checkboxes as the single source of truth for its selection state. It maps UI changes directly to visual visibility tokens, allowing items to be filtered immediately in the DOM. The checked state of standard inputs is the sole contract.
Architectural Design Features
-
Attribute & Tabular Modes: Toggles visibility of generic list items matching
data-{key}="{value}"attributes, or filters standard HTML<table>rows by parsing cell text inside Column IndexN. - Multi-Column AND Composition: Multiple filter instances can coordinate on the same native table target with different column indices (e.g. Department and Status). Checkboxes within a single column are evaluated with OR logic, while filters across different columns combine with AND logic.
-
Authored Checklists & Local Persistence: Filter options are authored directly in markup or rendered via domain templates (such as
ln-options). Addingdata-ln-persistautomatically remembers active checkbox selections across page reloads.
For the full guide see the ln-filter README and the architecture reference.
Attributes
| Attribute | On element | Description |
|---|---|---|
data-ln-filter="targetId" | component root | Target element by ID whose children are filtered |
data-ln-filter-key="field" | <input type="checkbox"> | Name of data attribute for comparison on target children |
data-ln-filter-value="val" | <input type="checkbox"> | Value for comparison |
data-ln-filter-reset | <input type="checkbox"> | Marks the "All" (reset) checkbox. Replaces data-ln-filter-value="" which still works as fallback. |
data-ln-filter-hide | target children | Set by JS when element doesn't match |
data-ln-filter-col | Component root | Column index (0-based) for table row filtering. Reads <td> text at column N. |
Basic Filter
- Ana Petrova — UI Designer
- Marko Nikolov — Frontend Developer
- Ivan Stojanovski — Backend Developer
- Sara Dimitrova — QA Engineer
- Elena Ristova — UX Designer
- Toni Angelov — QA Lead
- Boris Ilievski — Full Stack Developer
Filter with Cards
- Project Alpha Status: Active
- Project Beta Status: Pending
- Project Gamma Status: Inactive
- Project Delta Status: Active
- Project Epsilon Status: Pending
- Project Zeta Status: Active
Filter + Search Combination
Both components work independently on the same list — an item is visible only when neither hides it.
- Maja Kostadinova — HR Manager
- Petar Blazevski — System Administrator
- Kristina Gjorgjevska — Accountant
- Aleksandar Naumov — DevOps Engineer
- Vesna Todorova — HR Specialist
- Darko Mitevski — Financial Analyst
- Lidija Petrovska — Security Engineer
Driving filter state from outside
ln-filter has no imperative API. External code drives state by setting input.checked on the filter's checkboxes and dispatching a bubbling change event.
- Task A — High priority
- Task B — Medium priority
- Task C — Low priority
- Task D — High priority
- Task E — Medium priority
Table Column Filter (Hardcoded)
Filter a plain <table> by column text. No data-* attributes needed on rows.
| # | Name | Department | Status |
|---|---|---|---|
| 1 | Ana Petrova | Engineering | Active |
| 2 | Marko Nikolov | Design | Active |
| 3 | Ivan Stojanovski | Engineering | Inactive |
| 4 | Sara Dimitrova | Marketing | Active |
| 5 | Elena Ristova | Design | Pending |
| 6 | Toni Angelov | Marketing | Inactive |
| 7 | Boris Ilievski | Engineering | Active |
Multi-Column Table Filter (AND logic)
Two filters on the same table: department (column 2) AND status (column 3). Combined with AND logic across columns.
| # | Name | Department | Status |
|---|---|---|---|
| 1 | Ana Petrova | Engineering | Active |
| 2 | Marko Nikolov | Design | Active |
| 3 | Ivan Stojanovski | Engineering | Inactive |
| 4 | Sara Dimitrova | Marketing | Active |
| 5 | Elena Ristova | Design | Pending |
| 6 | Toni Angelov | Marketing | Inactive |
| 7 | Boris Ilievski | Engineering | Active |
Column Filter with Searchable Options
Column filter with authored options where a search input filters the checkbox list options dynamically.
| # | Name | Department | Role |
|---|---|---|---|
| 1 | Ana Petrova | Engineering | Senior Dev |
| 2 | Marko Nikolov | Design | UI Designer |
| 3 | Ivan Stojanovski | Engineering | Backend Dev |
| 4 | Sara Dimitrova | Marketing | Content Lead |
| 5 | Elena Ristova | Design | UX Researcher |
| 6 | Toni Angelov | QA | QA Engineer |
| 7 | Boris Ilievski | Engineering | DevOps |
| 8 | Kristina Gjorgjevska | Finance | Accountant |
| 9 | Darko Mitevski | Finance | Analyst |
| 10 | Maja Kostadinova | HR | HR Manager |
Events
| Event | Bubbles | detail |
|---|---|---|
ln-filter:change | yes | { key, values: [], targetId } |
ln-filter:reset | yes | { targetId } |
document.addEventListener('ln-filter:change', function (e) {
console.log('Filter:', e.detail.key, '=', e.detail.values.join(', '), 'target:', e.detail.targetId);
});
document.addEventListener('ln-filter:reset', function (e) {
console.log('Filter reset');
});
Required CSS
The hide rule is bundled in ln-ashlar. Pill styling (active state highlight) is automatic via label:has(> input:checked) in the library defaults — no additional CSS needed for active state.
/* Combined with ln-search */
[data-ln-search-hide],
[data-ln-filter-hide] {
display: none;
}