I'm currently working on a custom element which is basically a slightly augmented version of an input element, hosting all of its building blocks (including an input element) in a shadow DOM.
When the internal input element has focus, the host element should be styled with a colored outline and box-shadow, as seen below:
Therefore the focus and blur event handlers of the input toggle an attribute "focussed" on the host element with the encapsulated styles looking like this:
:host([focussed]) {
transition: outline 0.3s ease-in-out;
outline-color: var(--focus-color, var(--default-focus-color)) !important;
box-shadow: 0px 0px 3px var(--focus-color, var(--default-focus-color)) !important;
}
What I don't like about this approach:
Exposing a custom attribute on the host that needs to be observed, in order to ensure the correctness of the visually represented state (e.g. consumer calls setAttribute('focussed', '')
)
Alternatives I considered:
Of course my first thought was to encapsulate the attribute within the shadow DOM (or even toggle a class) on a container element filling out the space of the host element, but the problem is that overflowing contents such as outline and box-shadow seem to be forcefully hidden by the host element - which seems kind of logical.
I could dictate a fixed padding on the host element to ensure the visibility of the outline and shadow, but this would require considering different browser rendering behaviour of box-shadow and would feel counter-intuitive for custom styling by the consumer.
I'm looking for a best practice approach here and I would very much appreciate your educated thoughts on this one.
this.attachShadow({
mode: 'open',
delegatesFocus: true
})
works in Chrome, Edge, Opera, not the others (yet)
This styles the input (in shadowDOM) itself with:
:focus {
transition: outline 1s ease-in-out;
outline: 2px solid var(--focus-color,blue);
box-shadow: 10px 0px 10px var(--focus-shadow-color,red);
}
And styles the host element with (global) CSS:
:focus {
outline: 5px solid green;
}
Full explanation and playground JSFiddle
use Chrome/Edge/Opera first, then see lacking behaviour in others:
https://jsfiddle.net/WebComponents/Lpqyg201/
It has some pointers for click/focus/blur workarounds.
For FireFox , Safari support I would add something not too fancy that can easily be removed.
For now it is unclear to me what the time frame at Mozilla and Apple is,
maybe Supersharp knows