PostCSS plugin that transforms :focus-visible pseudo-class selectors into compatible class-based selectors for cross-browser support
npx @tessl/cli install tessl/npm-postcss-focus-visible@10.0.0PostCSS Focus Visible is a PostCSS plugin that transforms :focus-visible pseudo-class selectors into compatible class-based selectors for cross-browser support. It implements the CSS Selectors Level 4 specification for :focus-visible, providing better accessibility by distinguishing between keyboard and mouse focus states.
npm install postcss-focus-visible --save-devES Modules (preferred):
import postcssFocusVisible from "postcss-focus-visible";For TypeScript with options:
import postcssFocusVisible, { pluginOptions } from "postcss-focus-visible";CommonJS:
const postcssFocusVisible = require("postcss-focus-visible");The plugin transforms :focus-visible selectors into class-based equivalents that work with the focus-visible polyfill:
const postcss = require('postcss');
const postcssFocusVisible = require('postcss-focus-visible');
postcss([
postcssFocusVisible()
]).process(yourCSS);Input CSS:
:focus:not(:focus-visible) {
outline: none;
}Output CSS (with default options):
:focus:not(.focus-visible).js-focus-visible, .js-focus-visible :focus:not(.focus-visible) {
outline: none;
}
:focus:not(:focus-visible) {
outline: none;
}Creates a PostCSS plugin instance with optional configuration.
/**
* Creates a PostCSS plugin that transforms :focus-visible pseudo-selectors
* @param opts - Optional plugin configuration
* @returns PostCSS plugin instance
*/
function postcssFocusVisible(opts?: pluginOptions): PostCSS.Plugin;The plugin automatically:
:focus-visible pseudo-classes in selectors.focus-visible).js-focus-visible)Plugin behavior can be customized through the options parameter.
interface pluginOptions {
/** Preserve the original notation. default: true */
preserve?: boolean;
/** The replacement class to be used in the polyfill. default: ".focus-visible" */
replaceWith?: string;
/** Disable the selector prefix that is used to prevent a flash of incorrectly styled content. default: false */
disablePolyfillReadyClass?: boolean;
}preserve (boolean, default: true)
true: Keeps both original and transformed selectors in outputfalse: Removes original selectors, leaving only transformed onesExample with preserve: false:
postcssFocusVisible({ preserve: false })Input:
:focus:not(:focus-visible) {
outline: none;
}Output:
:focus:not(.focus-visible).js-focus-visible, .js-focus-visible :focus:not(.focus-visible) {
outline: none;
}replaceWith (string, default: ".focus-visible")
Defines the replacement selector for :focus-visible. Must be compatible with the focus-visible polyfill if used.
Example with custom replacement:
postcssFocusVisible({ replaceWith: '[data-focus-visible-added]' })Input:
:focus:not(:focus-visible) {
outline: none;
}Output:
:focus:not([data-focus-visible-added]).js-focus-visible, .js-focus-visible :focus:not([data-focus-visible-added]) {
outline: none;
}
:focus:not(:focus-visible) {
outline: none;
}disablePolyfillReadyClass (boolean, default: false)
Controls whether selectors are prefixed with the polyfill-ready class (.js-focus-visible). The polyfill-ready class ensures styles only apply when the polyfill is loaded and active.
Example with disabled polyfill-ready class:
postcssFocusVisible({ disablePolyfillReadyClass: true })Input:
:focus:not(:focus-visible) {
outline: none;
}Output:
:focus:not(.focus-visible) {
outline: none;
}
:focus:not(:focus-visible) {
outline: none;
}The plugin function includes standard PostCSS plugin properties.
/**
* PostCSS plugin flag indicating this is a valid PostCSS plugin
*/
postcssFocusVisible.postcss: true;npx postcss src/*.css --use postcss-focus-visible --dir destmodule.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-focus-visible')()
]
}
}
}
]
}
]
}
};Create a postcss.config.js file:
module.exports = {
plugins: [
require('postcss-focus-visible')({
preserve: true,
replaceWith: '.focus-visible'
})
]
};This plugin is designed to work with the focus-visible polyfill. The polyfill should be included in your JavaScript bundle:
npm install focus-visibleimport 'focus-visible';The polyfill automatically:
.js-focus-visible class to the document when loaded.focus-visible class on focused elements based on focus methodThe plugin includes built-in error handling for malformed selectors:
:focus-visible pseudo-classes are skipped:focus-visible support (Chrome 86+, Firefox 85+, Safari 15.4+)