Skip to content

Filter table with client side selection - #4616

Open
BrettJephson wants to merge 17 commits into
mainfrom
claude/table-slug-filter
Open

BrettJephson wants to merge 17 commits into
mainfrom
claude/table-slug-filter

Conversation

@BrettJephson

@BrettJephson BrettJephson commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Choosing an option in a tab or a select button now narrows any table or card grid whose Select column offers it. For example, a Platform column follows a macOS tab; a Status column is left alone.

Matching is on the option's label, slugified the way tab titles are, so a table and the tabs beside it agree. Most recent wins when a column offers several active options.

Screenshot 2026-09-18 at 09 05 50

🤖 Generated with Claude Code

BrettJephson and others added 4 commits September 16, 2026 07:17
A select column already declares its option set, and the reader already has a
selection driving tabs across the site. Join them: choosing "macOS" anywhere on
the page narrows a Platform column to macOS, and leaves a Status column alone
because it offers nothing by that name.

Where a column offers several active options the most recent wins, the rule tabs
resolve with, so a table and the tabs beside it agree.

Records are now built whenever the table has a select column, not only when its
search bar shows — a card grid hides that bar by default, and without records
there is nothing to match against. The picker or tab that set the slug is the
control for clearing it, and a reader can still change the filter by hand; the
next activation drives it again.

Resolution subscribes through a string snapshot rather than the recency list, so
a selection that changes nothing for this table re-renders nothing — the reason
useSelect stopped exposing that list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cDq5dtdh4eGcpekaqtCxE
@changeset-bot

changeset-bot Bot commented Sep 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0a2bd12

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
gitbook Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@argos-ci

argos-ci Bot commented Sep 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
customers-v2-cloudflare (Inspect) 👍 Approved by Brett Jephson 2 changed, 2 ignored Sep 21, 2026, 1:03 PM
customers-v2-vercel (Inspect) 👍 Approved by Brett Jephson 2 changed, 3 ignored Sep 21, 2026, 1:01 PM
v2-cloudflare (Inspect) 👍 Approved by Brett Jephson 5 changed, 1 ignored Sep 21, 2026, 1:04 PM
v2-vercel (Inspect) 👍 Approved by Brett Jephson 1 changed, 1 ignored Sep 21, 2026, 1:04 PM

@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Style invalidation on a large API reference

Elements restyled by opening one popup on the Snyk API reference. A share near or above 100% means the insertion restyles the whole document.

interaction restyled page share budget
openapi-select 8 10,804 0.1% 25%
search 631 10,804 5.8% 125%

@BrettJephson BrettJephson self-assigned this Sep 16, 2026
@BrettJephson BrettJephson changed the title Narrow a table to the reader's content selection Filter table with client side selection Sep 16, 2026
@BrettJephson

Copy link
Copy Markdown
Contributor Author

Blocker found in review — must fix before this leaves draft.

The slug filter can narrow a table with no visible indication and no way to clear it. shouldShowTableSearch is searchOverride ?? (recordCount >= 7 && viewType === 'grid'), so the filter controls are absent in three common cases:

  • cards view — always, by default
  • grid tables under 7 rows
  • any table where the author set search: false

In those cases a reader sees fewer rows than the author wrote, with nothing saying why. I had argued earlier that "the tab that set the slug is the control" — that's wrong: the tab is often on a different page, so the reader arrives at an already-narrowed table with no nearby control at all.

Second half, and the sharper one: the reader's own filter change is component state while the slug is in localStorage, so a reload always reasserts the slug filter. The reader can't override it durably.

Proposed fix: show a "Filtered to macOS · Clear" affordance whenever the slug filter is active, independent of the search bar, and have Clear call the store's existing deactivate(slug) so the override persists without new storage.

A narrowed table showed no sign of being narrowed and offered no way out.
The filter controls are absent on cards, on grids below the row threshold and
wherever an author turned search off, so in those cases a reader simply saw
fewer rows than the author wrote. The tab that set the slug is usually on
another page, so it is not the control either.

The notice renders independently of the search bar, and Clear goes through
the store's `deactivate` rather than local state: the selection is what
persists, so only dropping it there stops the filter returning on the next
load. Clearing is site-wide, so a tab elsewhere reverts too.

The effect that applies the filter now reconciles against the columns it
narrowed last, instead of only ever adding, so a new selection or a clear
undoes the previous one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cDq5dtdh4eGcpekaqtCxE
@BrettJephson

Copy link
Copy Markdown
Contributor Author

Blocker addressed in 4604ff4.

  • A TableSelectionFilter notice renders independently of the search bar — "Filtered to macOS" with a Clear — so cards, short grids and search: false tables get it too. That was the whole invisible-filter class, not just the cards case.
  • Clear calls the store's deactivate, not local state. The selection is what persists, so dropping it there is what stops the filter returning on the next load. It is site-wide by design: a tab elsewhere on the page reverts to its default too.
  • The applying effect now reconciles against the columns it narrowed last instead of only ever adding, so a new selection — or a clear — undoes the previous one. Without that, clearing left the old filter applied.

New translation key table_filtered_by_selection added across all 39 language files, per the existing convention.

This also answers the earlier note about mirroring the store into state: the effect now synchronises with an external store and reconciles its own previous writes, which is the sanctioned use rather than mirroring a derived value.

Still open from the original list: the brief unfiltered paint before the filter applies. Tabs avoid it with pre-paint CSS; rows have no equivalent yet.

"Filtered to macos" restated what the column dropdown beside it already
showed, so the two read as duplicates — when only one of them actually works:
clearing in the dropdown resets local state and the filter returns on the
next load.

Now "Matching your selection: macOS" with a "Clear selection" button, so the
line names the thing it owns, and sits tighter under the search bar rather
than floating as a caption on the table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cDq5dtdh4eGcpekaqtCxE
BrettJephson and others added 3 commits September 17, 2026 22:03
"Matches selection" rather than "Matching your selection", the clear reduced
to a cross whose label survives as its tooltip and accessible name, and the
line moved under the filter control it belongs to — position and copy carry
the association, so the button no longer has to spell it out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cDq5dtdh4eGcpekaqtCxE
The notice could go on claiming "Matches selection: macOS" after the reader
had filtered the column to something else, and the next page load would
quietly restore the filter they had just replaced — the selection persisted
while their change did not.

A change to a column the selection is driving is now a change to the
selection. Narrowing to a single option moves it there, so a tab elsewhere
follows; clearing the column, or picking several options at once, releases
it, since the selection holds one choice and cannot express either. Columns
the selection is not driving are left alone, so ordinary table filtering
never reaches across the page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cDq5dtdh4eGcpekaqtCxE
The effect reassigned its record of the narrowed columns inside the
setSelectedOptions updater. React can invoke an updater more than once with
the same input, and on the second pass that record was already empty, so an
empty selection took the early return and handed back the unchanged state —
React keeps the last result, so the clear was silently undone. Applying a
selection was unaffected, being idempotent, which is why only clearing broke.

The fold is now a pure `reconcileSelectedOptions`, given the previously
narrowed columns rather than reading them from the ref, and the ref is
updated in the effect body. Tested for repeat application.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cDq5dtdh4eGcpekaqtCxE
Changing a filter is not changing your mind about the selection: the filter
belongs to one table for one visit, while the selection is site-wide and
persists, so only the clear beside the notice should drop it. Reverts the
write-back that moved or released the selection from a column's dropdown.

Divergence is handled by the notice instead of by the store. It now speaks
only for columns the selection narrowed and the reader has left alone, so a
column they have filtered themselves drops out rather than being described as
matching. The selection stays active underneath and seeds the filter again on
the next load.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cDq5dtdh4eGcpekaqtCxE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant