feat(table): collapse the filter button group into a dropdown on small screens - #2137
Merged
Conversation
…l screens A filter group of more than a few categories outgrows a narrow viewport and overflows its row. `filter-responsive` swaps it for a dropdown below the site's main breakpoint. Off by default, so every existing table keeps its button group at all widths, and a no-op at `xs`, which has no display-utility infix to hide the group with — the same guard `wrap` already applies. The dropdown carries no behavior of its own. Each item names a filter button through `data-link`, and nav.js replays the click on it, so filtering still runs through the one handler and keeps composing with sorting, paging and search. Extracts nav.html's inline nav-dropdown into assets/panel-dropdown.html so both callers share it. Every tag, class and attribute is carried over unchanged; only the emitted indentation differs, since the markup no longer sits nested inside nav.html. Generalizes nav.js's companion sync to delegate from the `[data-companion]` group and resolve the control with `closest`, rather than assuming a nav's `button > li > ul` nesting. A nav and a button group now both reach their dropdown, so neither strands a stale label when the viewport crosses the breakpoint. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
The dropdown hardcoded the first entry as active, so a nav using `nav-show` to
open on a later tab advertised the wrong one: the toggle read "Tab 1" while
Tab 3 was the tab actually showing, and the dropdown marked "Tab 1" as active.
Selecting a tab fixed the label, so the mismatch only showed on first paint —
which is exactly when a reader looks at it.
`nav-show` names its entry by item id rather than position, so nav.html resolves
it to an index using the same `{args.id}-btn-{index}` expression its own buttons
use, and passes it to the dropdown as `active`. Falls back to the first entry
when `nav-show` is unset or names an item that does not exist.
Pre-existing, and carried over unchanged when the inline nav-dropdown was
extracted; the extraction only made it easy to see. The table filter group has
no equivalent case, since its "All" button is always the initial one.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
✅ Deploy Preview for gethinode-demo ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Collaborator
Author
|
Docs companion: gethinode/mod-docs#139 — hold that one until this ships in v3.22.0, or its example will pass an argument the released theme does not recognize. |
Collaborator
Author
|
🎉 This PR is included in version 3.22.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
filter-responsiveto thetableshortcode: below the site's main breakpoint the filter button group is replaced by a dropdown, for groups with more categories than a narrow viewport can hold.Off by default, so every existing filtered table renders its button group at all widths, exactly as before.
Why
A filter group of more than a few categories overflows its row on a phone. The nav component already solves this shape with a companion dropdown, so this reuses that mechanism rather than inventing a second one.
How it works
The dropdown carries no behavior of its own. Each item names a filter button through
data-link, andnav.jsreplays the click on it — so filtering still runs through the single existing handler and keeps composing with sorting, paging and search. No new filter JavaScript.Three supporting changes:
assets/panel-dropdown.html—nav.html's inlinenav-dropdownextracted into a shared partial so both callers use it. Every tag, class and attribute is carried over unchanged (including the double space indropdown-item text-nowrap, kept so the extraction reads as a move rather than a rewrite). Only the emitted indentation differs, since the markup no longer sits nested insidenav.html— verified by diffing a full example-site build againstmain.nav.js— the companion sync now delegates from the[data-companion]group and resolves the control withclosest, instead of assuming a nav'sbutton > li > ulnesting. A nav and a button group both reach their dropdown, so neither strands a stale label when the viewport crosses the breakpoint._shortcodes/table.html— forwards the new argument, which the shortcode's explicit allowlist would otherwise drop.filter-responsiveis defined inline indata/structures/table.ymlrather than inmod-utils, so this needs no module release. Note the globalresponsiveargument was not reused: it defaults totrue, which would have flipped every existing table into dropdown mode, andtable.ymlalready uses "responsive" to describe the horizontal-scroll wrapper.A no-op at
xs, which has no Bootstrap display-utility infix to hide the group with — the same guardwrapalready applies.Bug fix included
fix(nav): start the companion dropdown on the nav's own active entrypanel-dropdownhardcoded the first entry as active, so a nav usingnav-showto open on a later tab advertised the wrong one — the toggle read "Tab 1" while Tab 3 was the tab actually showing. Selecting a tab corrected it, so the mismatch only showed on first paint, which is when a reader looks at it.Pre-existing; the extraction only made it easy to see.
nav-shownames its entry by item id, sonav.htmlresolves it to an index using the same{args.id}-btn-{index}expression its own buttons use, and passes it asactive.Testing
New fixture in
exampleSite/content/en/table-demo.md(fixture-filter-responsive), with enough categories to overflow a narrow viewport.Driven in a browser at 390px and 1200px:
data-link→ real button → table filters. Rows went[widget, gadget, doohickey, thingamajig, whatsit]→[doohickey]; the real button tookactiveand the toggle relabeled.btn-groupwith no companion and no dropdown at 390px — default behavior unchanged.nav-showfixture's dropdown now renders "Tab 3", matching its active tab.pnpm lintclean,pnpm test:templatespasses, example site builds clean.Follow-ups (not in this PR)
mod-blocks'listcomponent forwardsfilter/filter_col/wrapbut notfilter-responsive, so component-rendered tables can't opt in until it does.