-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Docs: Add visible focus outline for keyboard navigation #33177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -255,6 +255,20 @@ export const DocsContent = styled.div(({ theme }) => { | |||||||||||
| color: theme.color.defaultText, | ||||||||||||
| '& code': code, | ||||||||||||
| }, | ||||||||||||
| // Ensure keyboard focus is visible for interactive elements inside docs | ||||||||||||
| [toGlobalSelector('a, button, input, textarea, select')]: { | ||||||||||||
| '&:focus-visible': { | ||||||||||||
| outline: | ||||||||||||
| theme.base === 'light' | ||||||||||||
| ? `2px solid ${theme.color.secondary}` | ||||||||||||
| : `2px solid ${theme.color.secondary}`, | ||||||||||||
|
Comment on lines
+261
to
+264
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
| outlineOffset: '2px', | ||||||||||||
| // fallback for high-contrast / forced-colors environments | ||||||||||||
| '@media (forced-colors: active)': { | ||||||||||||
| outline: '2px solid Highlight', | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
According to https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/outline-color, the default outline color is either currentColor or accent-color. Generally speaking I would prefer to not set a forced colour selector until someone reports an actual problem, though. We need to have some trust in the forced color selector applying system colours properly.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Sidnioulz Do you think we should avoid setting the color on the focus outline or am I misreading this comment?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Specifically talking about the forced colors selector which applies to High Contrast Mode. I prefer if we don't enforce system colours ourselves until someone reports a problem, because browsers already translate CSS colours into system colours themselves and do a pretty good job of it. Here for instance, I don't believe @Kamalllx chose the right semantic. Even if we set the right colour, there are a lot of deprecated system colours and a lot of not-yet-baseline system colours, so browser defaults will evolve over time, and we'll miss out on those browser changes when we hardcode system colours. |
||||||||||||
| }, | ||||||||||||
| }, | ||||||||||||
| }, | ||||||||||||
|
Comment on lines
+258
to
+271
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix
[toGlobalSelector('a, button, input, textarea, select')]: { ... }That expands to roughly: :where(a, button, input, textarea, select:not(...))which has two problems:
To keep the intended semantics and support all target elements, define the rule per element (you can refactor to share the style object if you prefer). For example: - // Ensure keyboard focus is visible for interactive elements inside docs
- [toGlobalSelector('a, button, input, textarea, select')]: {
- '&:focus-visible': {
- outline:
- theme.base === 'light'
- ? `2px solid ${theme.color.secondary}`
- : `2px solid ${theme.color.secondary}`,
- outlineOffset: '2px',
- // fallback for high-contrast / forced-colors environments
- '@media (forced-colors: active)': {
- outline: '2px solid Highlight',
- },
- },
- },
+ // Ensure keyboard focus is visible for interactive elements inside docs
+ const focusVisibleOutline = {
+ '&:focus-visible': {
+ outline: `2px solid ${theme.color.secondary}`,
+ outlineOffset: '2px',
+ // fallback for high-contrast / forced-colors environments
+ '@media (forced-colors: active)': {
+ outline: '2px solid Highlight',
+ },
+ },
+ };
+
+ [toGlobalSelector('a')]: focusVisibleOutline,
+ [toGlobalSelector('button')]: focusVisibleOutline,
+ [toGlobalSelector('input')]: focusVisibleOutline,
+ [toGlobalSelector('textarea')]: focusVisibleOutline,
+ [toGlobalSelector('select')]: focusVisibleOutline,(If you’d rather not introduce a new Also, note that the 🤖 Prompt for AI Agents |
||||||||||||
| [toGlobalSelector('pre')]: { | ||||||||||||
| ...reset, | ||||||||||||
| // reset | ||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd be better off targeting
toGlobalSelector('*:focus-visible'). We're missing things likearea,video controls,summary.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An explicit list is definitely going to be more performant than a
*, but the downside is the list might be difficult to maintain/remember over time. Just food for thought.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally speaking, we're splitting hairs here and we can ignore the performance overhead. What costs is how often you need to re-evaluate selectors rather than how many selectors you need to evaluate, because the eval is heavily optimised.
In this specific instance, I believe
*:focus-visiblehas the better performance. Selectors will be matched right to left and built into a tree-like index, so:focus-visiblepseudo-selector*Which is why
*provides the better performance here (fewer checks to make, as we know only focusable elements can get:focus-visibleand*:focus-visiblewill only apply rules when relevant).