# ally.style.focusSource
Differentiate the causes of focus change for when different visual styles need to applied.
# Description
The utility identifies pointer
(mouse, touch), key
(keyboard) and script
as sources for an element being focused. The information is made available to CSS via <html data-focus-source="key">
. The classes .focus-source-key
, .focus-source-pointer
, .focus-source-script
are made available on <html>
when the respective focus source occurs for the first time. When the utility is initialized, the focus source is <html data-focus-source="initial">
.
This module allows the document to style :focus
as follows:
body :focus {
/* default styling in case JS broke */
background: yellow;
}
html[data-focus-source="initial"] > body :focus {
/* styling for when focus was not changed yet */
background: green;
}
html[data-focus-source="pointer"] > body :focus {
/* styling for when focus was given by pointer (mouse, touch) */
background: red;
}
html[data-focus-source="key"] > body :focus {
/* styling for when focus was given by keyboard */
background: blue;
}
html[data-focus-source="script"] > body :focus {
/* styling for when focus was given by neither pointer nor keyboard */
background: orange;
}
html.focus-source-key > body :focus {
/* styling for when focus was changed at least once using the keyboard */
background: magenta;
}
The focus changes are also observed within the ShadowDOM, allowing the document styles to descend into the dark:
html[data-focus-source="pointer"] >>> :focus {
/* styling for when focus was given by pointer (mouse, touch) */
background: red;
}
/* older shadow-piercing-combinator notation */
html[data-focus-source="pointer"] /deep/ :focus {
/* styling for when focus was given by pointer (mouse, touch) */
background: red;
}
# Usage
var handle = ally.style.focusSource();
handle.disengage();
// get current focus source
handle.current(); // "key", "pointer", "script"
// test if a focus source has occurred at least once before
handle.used('key'); // true, false
// make all focus events use a specific source type
// regardless of the identified interaction type
handle.lock('pointer');
// revert locking into a specific source type
handle.unlock();
The identified focus source is retained when shifting focus to another element:
var handle = ally.style.focusSource();
element.addEventListener('click', function() {
otherElement.focus();
});
Use .lock()
to retain the identified focus source when shifting focus asynchronously:
var handle = ally.style.focusSource();
element.addEventListener('click', function() {
handle.lock(handle.current());
setTimeout(function() {
otherElement.focus();
handle.unlock();
});
});
# Returns
A <global-service>
interface, providing the handle.disengage()
method to stop the service.
# Service handle
The handle
is returned when engaging the service. As the <global-service>
interface describes, the handle.disengage()
method is provided to stop the service. Additionally the following methods are made available:
# handle.current()
The handle.current()
method does not accept any arguments and returns one of the following strings "key"
, "pointer"
, "script"
, depending on the current interaction type.
# handle.used(<string>
)
The handle.used()
method accepts one string argument and returns true
if that interaction type has ever been used before.
# handle.lock(<string>
)
The handle.lock()
method accepts one string argument and sets that as the interaction type for all subsequent handle.current()
invocations.
# handle.unlock()
The handle.unlock()
method releases the focus-source lock.
# Examples
# ally.style.focusSource Example
play with ally.style.focusSource Example on jsbin.com or open the document of ally.style.focusSource Example
# Changes
- In
v1.3.0
the methodhandle.unlock()
was added to supersedehandle.lock(false)
, which is still available, but removed from documentation.
# Related resources
- WICG: Exposing a user’s input modality and accompanying prollyfill
- CSS pseudo-class
:focus-ring