Open hsablonniere opened 4 years ago
Feedbacks from someone :wink:
- Focus should just be focus...no matter how it's achieved and people should design it to be nice enough to not worry about while still being visually distinct enough to support those who need it.
- We "write" :focus-visible (it's more of an automated process) but then PostCSS coverts this with https://www.npmjs.com/package/postcss-focus-visible for our output.
- We use https://www.npmjs.com/package/focus-visible to make it possible.
- "Be careful with this"
Here's a custom "polyfill" someone share with me for components with shadow DOM:
/**
* Lightweight implementation of focus-visible polyfill (https://github.com/WICG/focus-visible).
*
* Elements that should have visible focus, have the .focus-visible class added. In the official
* spec focus visible differs per user agent, for our purposes it's visible only when using
* keyboard navigation.
*
* See https://github.com/WICG/focus-visible/blob/master/src/focus-visible.js for full spec.
*/import { css } from 'lit-element';
import { listen, listenOnce } from '../utils/event.js';export const focusVisibleStyles = css`
.focus-visible:focus {
/* your styles go here */
}
`;// Set up document listeners to track whether the keyboard is being used.
let hadKeyboardEvent = false;['mousedown', 'pointerdown', 'touchstart'].forEach(name => {
document.addEventListener(
name,
() => {
hadKeyboardEvent = false;
},
true,
);
});document.addEventListener(
'keydown',
() => {
hadKeyboardEvent = true;
},
true,
);/**
* Observes focus visibility on the given target. This needs to be set up only once per
* shadowRoot boundary. For general most cases, the FocusVisibileMixin should be used.
*
* @param {HTMLElement} target
* @returns {() => void} Function which removes the event listener.
*/
export function observeFocusVisible(target) {
return listen(
target,
'focusin',
e => {
/** @type {HTMLElement} */
const focusTarget = (e.target);
// SVG elements don't have a classList
if (!focusTarget || !focusTarget.classList) {
return;
} // We cannot handle focus events fired from within shadow roots. It should be
// handled host element.
if (focusTarget.shadowRoot) {
return;
} if (hadKeyboardEvent) {
hadKeyboardEvent = false;
focusTarget.classList.add('focus-visible'); listenOnce(focusTarget, 'blur', () => {
focusTarget.classList.remove('focus-visible');
});
}
},
true,
);
}/**
* Calls and cleans up observeFocusVisible() for the element's shadowroot or host.
*/
export const FocusVisibleMixin = base =>
class extends base {
connectedCallback() {
if (super.connectedCallback) {
super.connectedCallback();
} this.__unlistenFocusVisible = observeFocusVisible(this.shadowRoot || this);
} disconnectedCallback() {
if (super.disconnectedCallback) {
super.disconnectedCallback();
} if (this.__unlistenFocusVisible) {
this.__unlistenFocusVisible();
}
}
};
@hsablonniere :focus-visible
is on the way (landing in Safari soon, in Safari TP at the moment).
In the meantime, we need to decide what we do:
Alsacreation suggests a way to switch back to basic :focus selector if :focus-visible is not supported:
*:focus {
outline: 6px dashed hotpink;
}
@supports selector(div:focus-visible) {
/* if :focus-visible is supported, hide :focus style defined right above */
*:focus:not(:focus-visible) {
outline-color: transparent;
}
/* rely on :focus-visible to provide outline only for keyboard users */
*:focus-visible {
outline: 6px dashed hotpink;
}
}
We can import the code above inside most of our components to avoid duplicating it (especially since it is quite verbose). However if one needs to customize it inside a component, they would need to override both :focus and :focus-visible styles to do so.
What I do not know at the moment is whether one would actually need to customize this and how often they would. What's your opinion on that @Galimede @hsablonniere ?
If you feel like there is a risk of over complicating things, we could simply rely on the :focus and change it to :focus-visible in 1 year or so. (this might actually the best option as long as making focus visible on click is not a problem for you).
We'll consider using the focus-visible
when/if we introduce a shared style module that all components import. (see #690)
For now, this subject in on standby.