generated from nl-design-system/example
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support both
:focus
and :focus-visible
- Loading branch information
Showing
39 changed files
with
457 additions
and
34 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<!-- | ||
@license EUPL-1.2 | ||
Copyright (c) 2021 Robbert Broersma | ||
--> | ||
|
||
# Focus | ||
|
||
In CSS there are two important pseudo-classes we use: `:focus` and `:focus-visible`. | ||
|
||
Browser support for [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) unfortunately [does not include Safari 15](https://caniuse.com/css-focus-visible). | ||
|
||
## Comparison | ||
|
||
`:focus`: | ||
|
||
- not visible on disabled interactive elements | ||
- only in this state for a very short time when a mouse click or touch interaction triggers activation, for components such as Button or Link | ||
- in this state for longer for elements that cannot be activated, such as a textbox | ||
- remains in this state after activiation for some components, such as checkbox | ||
- visual effect can vary a bit per component: | ||
- different background color | ||
- different border width | ||
- different border color | ||
- different text underline style | ||
|
||
`:focus-visible`: | ||
|
||
- visible even on disabled interactive elements | ||
- looks very similar accross components, because user needs to keep track of focused element | ||
- should draw attention | ||
|
||
## Design for `:focus` | ||
|
||
- The design for `:focus` should be distinguishable from the `:hover` design. When a user did not configure their system to always make focus visible using for example a focus ring, the user should be able to know which component will be activated when pressing `Enter`. When focus and hover state look the same, it might not possible to know which element would be activated. | ||
- When using color, use a consistent color to convey focus. Choose a color that can be combined with other states, such as combining the red color for invalid state with your color for focus state. | ||
- When changing the `font-weight` of a component as focus state, it might cause unintended layout shifts, so it might not be the ideal option. | ||
|
||
## Design for `:focus-visible` | ||
|
||
- A focus ring should not obscure the content inside the focused area. | ||
- A focus ring should not obscure surrounding content. This consideration can also affect the minimum space between focusable elements. | ||
- A focus ring should be visible with sufficient contrast on both dark and light backgrounds. | ||
- A focus ring should be visible on backgrounds with unknown and mixed colors, such as background images. | ||
- When using CSS with `overflow: hidden` in your component, the `outline` rendering can become partially or completely invisible. Be careful not to break the focus indication when using `overflow: hidden`. | ||
|
||
## Related reading | ||
|
||
- [Giving users and developers more control over focus - Chromium Blog](https://blog.chromium.org/2020/09/giving-users-and-developers-more.html) | ||
- [The Focus-Indicated Pseudo-class: `:focus-visible` - W3C Selectors specification](https://www.w3.org/TR/selectors-4/#the-focus-visible-pseudo) | ||
- [Understanding WCAG Success Criterion 2.4.7: Focus visible](https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-focus-visible.html) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* @license EUPL-1.2 | ||
* Copyright (c) 2021 Gemeente Utrecht | ||
* Copyright (c) 2021 Robbert Broersma | ||
*/ | ||
|
||
@mixin utrecht-focus-ring { | ||
box-shadow: 0 0 0 var(--utrecht-focus-box-shadow-spread-radius, 0) var(--utrecht-focus-box-shadow-color, transparent); | ||
outline-color: var(--utrecht-focus-outline-color, transparent); | ||
outline-offset: 0; | ||
outline-style: var(--utrecht-focus-outline-style, solid); | ||
outline-width: var(--utrecht-focus-outline-width, 0); | ||
} | ||
|
||
/* stylelint-disable-next-line block-no-empty */ | ||
@mixin utrecht-focus { | ||
} | ||
|
||
@mixin utrecht-focus-visible { | ||
@include utrecht-focus-ring(); | ||
} | ||
|
||
@mixin utrecht-focus-pseudo-classes { | ||
:focus { | ||
@include utrecht-focus; | ||
} | ||
:focus-visible { | ||
@include utrecht-focus-visible; | ||
} | ||
} |
File renamed without changes.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import { Canvas, Description, Meta, Story } from "@storybook/addon-docs"; | ||
import clsx from "clsx"; | ||
import { ComponentTokensTable } from "../../../documentation/components/ComponentTokensTable"; | ||
import tokens from "../../../proprietary/design-tokens/dist/index.json"; | ||
import readme from "./README.md"; | ||
|
||
export const bem = (block, modifiers, classNames) => | ||
clsx( | ||
block, | ||
classNames, | ||
modifiers && | ||
Object.fromEntries( | ||
Object.entries(modifiers) | ||
.filter(([key]) => key) | ||
.map(([key, value]) => [`${block}--${key}`, value]) | ||
) | ||
); | ||
|
||
export const FocusHTMLExample = () => ` | ||
<div class="utrecht-html"> | ||
<div><a href="https://example.com" target="_new">example.com</a></div> | ||
<div><input type="text"></div> | ||
<div><input type="checkbox"></div> | ||
<div><input type="radio"></div> | ||
<div><select><option>Example</option></select></div> | ||
<div><textarea></textarea></div> | ||
<div><button type="button">Click me</button></div> | ||
</div> | ||
`; | ||
|
||
export const FocusBEMExample = ({ modifiers = {} }) => ` | ||
<div> | ||
<div><a href="https://example.com" target="_new" class="${bem("utrecht-link", modifiers)}">example.com</a></div> | ||
<div><input type="text" class="${bem("utrecht-textbox", modifiers, "utrecht-textbox--html-input")}"></div> | ||
<div><input type="checkbox" class="${bem("utrecht-checkbox", modifiers, "utrecht-textbox--html-input")}"></div> | ||
<div><input type="radio" class="${bem("utrecht-radio-button", modifiers, "utrecht-textbox--html-input")}"></div> | ||
<div><select class="${bem( | ||
"utrecht-select", | ||
modifiers, | ||
"utrecht-select--html-select" | ||
)}"><option>Example</option></select></div> | ||
<div><textarea class="${bem("utrecht-textarea", modifiers, "utrecht-textarea--html-textarea")}"></textarea></div> | ||
<div><button type="button" class="${bem("utrecht-button", modifiers)}">Click me</button></div> | ||
</div> | ||
`; | ||
|
||
<Meta title="Common Patterns/Focus" /> | ||
|
||
<Description>{readme}</Description> | ||
|
||
## Example | ||
|
||
### Focusable | ||
|
||
<Canvas> | ||
<Story | ||
name="Focus with BEM" | ||
parameters={{ | ||
docs: { | ||
transformSource: (_src, { args }) => FocusBEMExample(args), | ||
}, | ||
percy: { skip: true }, | ||
}} | ||
> | ||
{FocusBEMExample.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
### Focused | ||
|
||
<Canvas> | ||
<Story | ||
name="Focus with BEM and :focus" | ||
parameters={{ | ||
docs: { | ||
transformSource: (_src, { args }) => FocusBEMExample(args), | ||
}, | ||
percy: { skip: true }, | ||
}} | ||
args={{ | ||
modifiers: { | ||
focus: true, | ||
}, | ||
}} | ||
> | ||
{FocusBEMExample.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
### Focus visible | ||
|
||
<Canvas> | ||
<Story | ||
name="Focus with BEM and :focus-visible" | ||
parameters={{ | ||
docs: { | ||
transformSource: (_src, { args }) => FocusBEMExample(args), | ||
}, | ||
percy: { skip: true }, | ||
}} | ||
args={{ | ||
modifiers: { | ||
"focus-visible": true, | ||
}, | ||
}} | ||
> | ||
{FocusBEMExample.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
### Focus and focus visible | ||
|
||
<Canvas> | ||
<Story | ||
name="Focus with BEM and both :focus and :focus-visible" | ||
parameters={{ | ||
docs: { | ||
transformSource: (_src, { args }) => FocusBEMExample(args), | ||
}, | ||
percy: { skip: true }, | ||
}} | ||
args={{ | ||
modifiers: { | ||
focus: true, | ||
"focus-visible": true, | ||
}, | ||
}} | ||
> | ||
{FocusBEMExample.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
### Focusable HTML | ||
|
||
<Canvas> | ||
<Story | ||
name="Focus with HTML" | ||
parameters={{ | ||
docs: { | ||
transformSource: (_src, { args }) => FocusHTMLExample(args), | ||
}, | ||
percy: { skip: true }, | ||
}} | ||
> | ||
{FocusHTMLExample.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
## Design Tokens | ||
|
||
<ComponentTokensTable tokens={tokens} component="utrecht-focus"></ComponentTokensTable> |
This file contains 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
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.