or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-postcss-focus-visible

PostCSS plugin that transforms :focus-visible pseudo-class selectors into compatible class-based selectors for cross-browser support

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/postcss-focus-visible@10.0.x

To install, run

npx @tessl/cli install tessl/npm-postcss-focus-visible@10.0.0

index.mddocs/

PostCSS Focus Visible

PostCSS 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.

Package Information

  • Package Name: postcss-focus-visible
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install postcss-focus-visible --save-dev

Core Imports

ES 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");

Basic Usage

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;
}

Capabilities

Main Plugin Function

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:

  • Detects :focus-visible pseudo-classes in selectors
  • Replaces them with configurable class selectors (default: .focus-visible)
  • Adds polyfill-ready class prefixes for compatibility (default: .js-focus-visible)
  • Preserves original selectors alongside transformed ones (configurable)

Configuration Options

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 output
  • false: Removes original selectors, leaving only transformed ones

Example 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;
}

Plugin Properties

The plugin function includes standard PostCSS plugin properties.

/**
 * PostCSS plugin flag indicating this is a valid PostCSS plugin
 */
postcssFocusVisible.postcss: true;

Integration Patterns

With PostCSS CLI

npx postcss src/*.css --use postcss-focus-visible --dir dest

With Webpack and postcss-loader

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  require('postcss-focus-visible')()
                ]
              }
            }
          }
        ]
      }
    ]
  }
};

With PostCSS Load Config

Create a postcss.config.js file:

module.exports = {
  plugins: [
    require('postcss-focus-visible')({
      preserve: true,
      replaceWith: '.focus-visible'
    })
  ]
};

Polyfill Integration

This plugin is designed to work with the focus-visible polyfill. The polyfill should be included in your JavaScript bundle:

npm install focus-visible
import 'focus-visible';

The polyfill automatically:

  • Adds the .js-focus-visible class to the document when loaded
  • Manages the .focus-visible class on focused elements based on focus method
  • Provides consistent behavior across all browsers

Error Handling

The plugin includes built-in error handling for malformed selectors:

  • Invalid CSS selectors are logged as warnings and left unchanged
  • Malformed :focus-visible pseudo-classes are skipped
  • Processing continues for valid selectors even if some fail to parse

Browser Compatibility

  • Modern browsers: Native :focus-visible support (Chrome 86+, Firefox 85+, Safari 15.4+)
  • Legacy browsers: Requires focus-visible polyfill for full functionality
  • Node.js: Requires Node.js 18+ (as specified in package engines)

Dependencies

  • postcss-selector-parser: CSS selector parsing and manipulation (runtime dependency)
  • postcss: PostCSS framework (peer dependency ^8.4)