Skip to content

[Button] Fix Next/Previous buttons staying in clicked state - #7941

Open
vermarjun wants to merge 2 commits into
layer5io:masterfrom
vermarjun:fix/7940-button-stuck-focus-state
Open

[Button] Fix Next/Previous buttons staying in clicked state#7941
vermarjun wants to merge 2 commits into
layer5io:masterfrom
vermarjun:fix/7940-button-stuck-focus-state

Conversation

@vermarjun

@vermarjun vermarjun commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes #7940

Notes for Reviewers

The stuck state comes from reusecore/Button, not from the pagination component.

The base ButtonStyle rule paints :hover and :focus with the same declaration:

&:hover,
&:focus {
    color: white;
    background: ${props => props.theme.activeColor};   // #3C494F in both themes
}

The three variant blocks below it all re-declare :hover. None of them re-declare :focus. A mouse click leaves the button focused, so the base :focus rule keeps winning and the button sits at #3C494F until focus moves. Clicking anywhere else blurs it, which is the "only comes back after clicking somewhere else" part of the report.

The change scopes that base rule to :focus-visible. Browsers don't match :focus-visible when a button is clicked with a pointer, so the button drops straight back to its own color. They do match it on tab, so keyboard users keep the same focus indicator they had before.

Measured on /resources with gatsby develop, reading computed background-color after a real click with the pointer moved off the button:

button at rest after click, before after click, with fix
Next $primary #EBC017 #3C494F #EBC017
Previous $secondary #00B39F #3C494F #00B39F

Tab focus still resolves to #3C494F on both, so nothing is lost for keyboard navigation.

Before, after clicking Next:

After:

Two notes:

  1. Next and Previous were only the visible case. The rule lives on the shared button, so every $primary, $secondary and $outlined button on the site held the dark state after a click.
  2. btn.style.js isn't prettier formatted on master, so the lint-staged pre-commit hook rewrites the whole file (75 insertions, 71 deletions) alongside the fix. I committed with --no-verify to keep this reviewable at one line. Happy to push the reformat as a separate commit if you want it.

Signed commits

  • Yes, I signed my commits.

Summary by CodeRabbit

  • Style
    • Updated button focus styling to appear during keyboard navigation, reducing focus-ring display during mouse or touch interactions.

The base ButtonStyle rule paints both :hover and :focus with the dark
activeColor (#3c494f), but the $primary, $secondary and $outlined variant
blocks only re-declare :hover. A mouse click leaves the button focused, so
the base :focus rule wins and the button stays dark until the user clicks
somewhere else.

Scope that base rule to :focus-visible. A mouse click no longer triggers it,
and keyboard focus keeps its visible indicator.

Fixes layer5io#7940

Signed-off-by: vermarjun <vermarjun26@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f0b2cf23-1412-4d54-be83-0043369433cf

📥 Commits

Reviewing files that changed from the base of the PR and between e4c77a5 and cff8761.

📒 Files selected for processing (1)
  • src/reusecore/Button/btn.style.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/reusecore/Button/btn.style.js

📝 Walkthrough

Walkthrough

The button focus selector changed from :focus to :focus-visible. Other button styling was reformatted without behavioral changes.

Changes

Button focus behavior

Layer / File(s) Summary
Update button focus selector
src/reusecore/Button/btn.style.js
Button focus styling now applies only to :focus-visible states. Other styling remains unchanged.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Merge Risk: ⚪ Minimal · up to cff87

This localized styling change restores the intended button colors after pointer clicks while preserving keyboard focus indication; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: pontusringblom

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the fix for buttons remaining in a clicked state.
Linked Issues check ✅ Passed The focus-visible change addresses issue #7940 by preventing pointer clicks from retaining focus styling while preserving keyboard focus indication.
Out of Scope Changes check ✅ Passed The changes are limited to the shared button focus selector and related formatting, which supports the linked issue objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@vermarjun

Copy link
Copy Markdown
Contributor Author

@leecalcote could you take a look when you get a chance? One line in reusecore/Button, swapping :focus for :focus-visible so a mouse click stops parking buttons in the dark activeColor state.

Two calls I'd like your read on:

  • It lands on every $primary, $secondary and $outlined button, not just the pagination pair in [Bug] Next and previous button stays in clicked state #7940, because the rule sits on the shared component.
  • I skipped the prettier hook so the diff stays at one line. Running it reformats all 86 lines of btn.style.js, which isn't prettier formatted on master today. Say the word and I'll push that as its own commit.

@leecalcote

Copy link
Copy Markdown
Member

@leecalcote could you take a look when you get a chance? One line in reusecore/Button, swapping :focus for :focus-visible so a mouse click stops parking buttons in the dark activeColor state.

Two calls I'd like your read on:

  • It lands on every $primary, $secondary and $outlined button, not just the pagination pair in [Bug] Next and previous button stays in clicked state #7940, because the rule sits on the shared component.
  • I skipped the prettier hook so the diff stays at one line. Running it reformats all 86 lines of btn.style.js, which isn't prettier formatted on master today. Say the word and I'll push that as its own commit.

Sure, @vermarjun. I'm taking a look...

@leecalcote leecalcote left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

The $primary, $secondary, $outlined blocks only override :hover, not :focus, yeah?

After this change a keyboard-focused variant button will still show the base activeColor rather than the variant's own color. How does this manifest in other button variants? Do we potentially need to add &:focus-visible to each variant block?

Prettier skipped? If --no-verify was used, let's get a follow up commit.

The file was not prettier formatted on master, so the lint-staged hook
rewrites it wholesale. Landing that as its own commit keeps the
:focus-visible fix in e4c77a5 reviewable at one line.

No behavior change.

Signed-off-by: vermarjun <vermarjun26@gmail.com>
@vermarjun

Copy link
Copy Markdown
Contributor Author

@leecalcote yes, that's right. $primary, $secondary and $outlined each re-declare &:hover and none of them touch :focus.

On whether they need their own &:focus-visible, I went and checked, and I think the answer is no. Mirroring each variant's hover into focus would make keyboard focus weaker rather than better. Here's what's actually in those blocks today:

variant at rest its own :hover
$primary #000000 on #EBC017 #000000 on #EBC017, box-shadow only
$secondary white on #00b39f white on #00d3a9, box-shadow
$outlined transparent, whiteToBlack border box-shadow only

$primary and $outlined hover to the exact colors they already sit at. Hover changes the shadow and nothing else. So if :focus-visible inherited that, tabbing to a Next button would leave it yellow with a faint shadow, which fails WCAG 2.4.7 far worse than what's there now.

Two things worth pulling apart here. The dark-on-keyboard-focus behavior isn't something this PR introduces. On master :focus already fires on tab, so a tabbed $primary goes #3c494f today. This change only removes the pointer case. Keyboard focus is identical before and after.

If you'd rather variants kept their own color while focused, I'd write it as an outline instead of a background swap:

&:focus-visible {
    outline: 3px solid ${props => props.theme.secondaryColor};
    outline-offset: 2px;
}

Every variant keeps its identity color, and a ring is easier to get right on contrast than recoloring three buttons. But it sets the focus language for the whole site, not just this file. btn.style.js is the only focus-visible in src/ right now, against 19 other &:focus rules. Happy either way, though my instinct is that belongs in its own PR rather than riding along with a one-line bug fix.

Prettier is done, pushed as cff8761 with the hook running this time.

One thing I ran into while doing it. npx prettier --write isn't idempotent on this file. The first pass indents the three variant blocks a level deeper, the second pass pulls them back, and it holds steady after that, so --check still fails right after a single write. .lintstagedrc.js runs eslint --fix then prettier --write once each, so the hook can't land on the stable output by itself. Nothing blocking, just worth knowing if this file shows up churny in a future diff.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for PR #7941 removed.

This PR preview was automatically pruned because we keep only the 3 most recently updated previews on GitHub Pages to stay within deployment size limits.

If needed, push a new commit to this PR to generate a fresh preview.

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.

[Bug] Next and previous button stays in clicked state

2 participants