LearnNewsExamplesServices
Frontmatter
id19793
titleGrid headers show when their column is filtered
stateClosed
labels
enhancementaigrid
assigneesneo-opus-ada
createdAtOct 16, 2026, 11:48 AM
updatedAtOct 16, 2026, 3:40 PM
githubUrlhttps://github.com/neomjs/neo/issues/19793
authorneo-opus-grace
commentsCount1
parentIssue19791
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 19792 Grid record search: the Store-wide search contribution and its counting
blocking[]
closedAtOct 16, 2026, 3:40 PM
milestonev13.3

Grid headers show when their column is filtered

Closed Backlog/active-chunk-9 enhancementaigrid
neo-opus-grace
neo-opus-grace commented on Oct 16, 2026, 11:48 AM

Context

This is the header active-state leaf of epic #19791, graduated from #19786 (contract 5, option H). I reproduced the defect live on dev 5829f5d407 in examples/grid/bigData, with header filters and column menus both on.

The Problem

After checking a value in the Firstname picker and clearing the Firstname header field, the grid stays filtered while its header looks unfiltered. The field is empty, the ▾ trigger is transparent once hover and focus leave, and no class or aria state marks the column. A user sees filtered rows and no reason for them.

The Architectural Reality

  • The menu plugin observes store.filters and the store's events, but scheduleRefresh returns while the surface is closed (src/grid/header/plugin/Menu.mjs:152). Nothing updates the header while the picker is shut.
  • The trigger shows only on :hover / :focus-within (resources/scss/src/grid/header/plugin/Menu.scss:17–19).
  • A column with showHeaderFilter and columnMenu: false has no plugin at all, but can still carry an effective filter.
  • A cleared header field keeps its filter with value: '', which is inert (Filter.mjs:250). "An owned filter exists" is therefore not "the column is filtered"; Filter.effective from the data-contract leaf of this epic answers the second.
  • Design authority: the graduated contract in #19786 (body SHA-256 72b90388…).

The Fix

grid.header.Button syncs its active state from the Store's filters and filter events, independently of the menu plugin. When an effective owned contribution (header-inline or header-picker) exists for its dataField, the header:

  • adds neo-grid-column-filtered, which the Menu.scss visibility rule also matches, so the trigger stays visible;
  • shows a filled glyph;
  • extends the trigger label to "Filter , active". ARIA has no filtered-columnheader attribute, so the label carries the state.

This leaf builds on the data-contract leaf's Filter.effective. Rebase on the landed #19788 (same file, onClick).

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
neo-grid-column-filtered (new header class) #19786 contract 5 Present while the column has an effective owned contribution Absent otherwise Button JSDoc, Menu.scss comment e2e: class read back
Trigger aria-label (Menu.mjs:93) #19786 contract 5 Adds ", active" while filtered Unchanged label when not filtered plugin JSDoc e2e: label read back
Menu.scss visibility rule #19786 contract 5 Also shows the trigger for filtered columns Hover and focus behavior unchanged scss screenshot

Decision Record impact: none. Decision Record: NOT_NEEDED.

Acceptance Criteria

  • The bigData drive (checked picker plus cleared field on one column) leaves the header class and the trigger label marked, and the trigger stays visible without hover.
  • A cleared header field alone (empty value) does not mark the column.
  • With showHeaderFilters on and columnMenu: false, an effective inline filter marks its header.
  • Clearing the last effective contribution unmarks the header, across header recreation and Store swap.
  • The existing header, menu and sort specs stay green, including #19788's.

Out of Scope

The toolbar summary (the epic's toolbar leaf), the header-filter layout (#19786 OQ8), and the Table header (#19790).

Related

#19791 · #19786 · #19788

Live latest-open sweep: newest open issues at 09:47Z, no equivalent. A2A claim sweep: no claim on header active state. MC sweep: "grid header active filter state invisible picker", no prior decision.

unowned-rationale: open for self-selection by the v13.3 pair (Emmy, Grace) or any peer. It touches the Button that #19788 (Emmy) changes, so it waits for that merge.

Origin Session ID: bb2e8968-a6d6-4ef7-a4ed-5ab3157b1ac8 Retrieval Hint: "grid header filtered column active state trigger visible effective contribution"

tobiu referenced in commit 09b2791 - "feat(grid): headers show when their column is filtered (#19793) (#19805) on Oct 16, 2026, 3:40 PM
tobiu closed this issue on Oct 16, 2026, 3:40 PM