Skip to content

Adjust for Vuetify 4.2.0 - #835

Merged
ajslater merged 3 commits into
developfrom
vuetify-4.2.0-fixes
Sep 2, 2026
Merged

Adjust for Vuetify 4.2.0#835
ajslater merged 3 commits into
developfrom
vuetify-4.2.0-fixes

Conversation

@ajslater

@ajslater ajslater commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Three adjustments for the Vuetify 4.2.0 bump in 6671173. Found by diffing the
4.1.12 and 4.2.0 sources rather than reading the release notes, which undersold
the silent changes.

None of these ever shipped: v2.3.0 is untagged, so the bump that caused them is
itself unreleased. No NEWS.md entry for that reason.

Unclip the settings button's progress ring

4.2.0 added overflow: hidden to .v-btn (fix(variant) #22992), making the
button both the containing block and the clip box for the admin overlays inside
it. The 32px librarian progress ring does not fit the 28px compact icon button,
so on xs it lost its left and bottom arcs. One declaration restores it. The
badge dots and the hamburger glyph were never at risk.

Keep the filter menu's extra rows keyboard reachable

4.2.0 moved select keyboard navigation into useScrolling, whose list keydown
capture wraps from either end of the item rows and calls
stopImmediatePropagation(). That pre-empts VList's own focus walk, which was
what carried the user from the bookmark rows into the rows this menu
contributes through its prepend/append slots, so "Clear All Filters",
"Favorites Only" and the filter sub-menus became mouse-only.

A capture listener on the overlay content runs before the list's, so stepping
off either end now lands on the adjacent slot row. Everything else is left
alone and Vuetify still owns the navigation. The neighbour is found by walking
the content's focusable rows rather than by naming the slot rows, so it follows
whatever is rendered: logged out there is no "Favorites Only" and the step
lands on the first filter sub-menu.

list-props cannot host this handler. It merges after Vuetify's own list
events, and Vue's array invoker stops the loop once stopImmediatePropagation
sets _stopped, so Vuetify silences a list-props handler at exactly the edge
rows that need it.

Drop the book change drawer's conditional width

The drawer is 33vw, not Vuetify's 256px default. 4.1 parked an inactive layout
item at translateX(-(width prop + 1)px), computed from the prop rather than
the rendered box, so a 33vw drawer stayed partly on screen when closed.
24f8d1b worked around that by applying the width only while open, which also
made closing shrink it from 33vw to 256px mid-slide. 4.2.0 parks it at
calc(+/-100% +/- 1px) of its own box, so the width is unconditional now and
the close is a plain slide.

Testing

Nine new tests in two files; the suite is 456 passing, make lint clean, and
the production build emits the intended CSS. The keyboard tests were
mutation-checked: removing the fix fails both reachability cases.

Still manual, and not covered here: the ring on a real phone with a librarian
job running, and the reader's swipe-to-turn on iOS Safari, which 4.2.0 also
changed by making v-touch ignore swipes that scrolled an ancestor. Notes for
both are in the audit plan.

🤖 Generated with Claude Code

ajslater and others added 3 commits September 2, 2026 11:52
Vuetify 4.2.0 added `overflow: hidden` to `.v-btn` (fix(variant) #22992),
which makes the button both the containing block and the clip box for the
admin overlays inside it. The 32px progress ring does not fit the 28px
compact icon button, so on xs it lost its left and bottom arcs; the
safe-area padding clips it on notched phones in landscape too.

Restore the pre-4.2 behavior for this one button. The scoped id selector is
unlayered so it wins without `!important`, and nothing escapes that the
Vuetify clip was meant to contain: `variant="plain"` hides the button
overlay, the ripple container clips itself, and inside `v-toolbar-items` the
button has no border radius.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Vuetify 4.2.0 moved select keyboard navigation into `useScrolling`, whose
list keydown capture wraps from either end of the item rows and calls
`stopImmediatePropagation()`. That pre-empts VList's own focus walk, which
was what used to carry the user from the bookmark rows into the rows this
menu contributes through the prepend/append slots, so "Clear All Filters",
"Favorites Only" and the filter sub-menus became mouse-only.

A capture listener on the overlay content runs before the list's, so
stepping off either end of the bookmark rows now lands on the adjacent slot
row instead of wrapping. Every other key and row is left alone and Vuetify
still owns the navigation. The neighbour is found by walking the content's
focusable rows rather than by naming the slot rows, so it follows the rows
that are actually rendered: logged out, there is no "Favorites Only" and the
step lands on the first filter sub-menu.

Also cover the other 4.2 delta in this menu: `closeOnSelect()` now bails
when `menuProps` carries `closeOnContentClick: false`, which leaves
`onSubMenuSelected` as the only thing closing the menu after a pick.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The drawer is 33vw rather than Vuetify's 256px default. Vuetify 4.1 parked
an inactive layout item at `translateX(-(width prop + 1)px)`, computed from
the prop and not the rendered box, so a 33vw drawer stayed partly on screen
when closed. 24f8d1b worked around that by applying the width only while
the drawer was open, which also made closing shrink it from 33vw to 256px
mid-slide.

Vuetify 4.2.0 parks it at `calc(+/-100% +/- 1px)` of its own rendered box,
so the width can be unconditional and the close is a plain slide. Tests pin
the offscreen transform that makes this safe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ajslater
ajslater merged commit a715db5 into develop Sep 2, 2026
1 check passed
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