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.00
# PostCSS Focus Visible
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: postcss-focus-visible
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install postcss-focus-visible --save-dev`
10
11
## Core Imports
12
13
ES Modules (preferred):
14
15
```typescript
16
import postcssFocusVisible from "postcss-focus-visible";
17
```
18
19
For TypeScript with options:
20
21
```typescript
22
import postcssFocusVisible, { pluginOptions } from "postcss-focus-visible";
23
```
24
25
CommonJS:
26
27
```javascript
28
const postcssFocusVisible = require("postcss-focus-visible");
29
```
30
31
## Basic Usage
32
33
The plugin transforms `:focus-visible` selectors into class-based equivalents that work with the focus-visible polyfill:
34
35
```javascript
36
const postcss = require('postcss');
37
const postcssFocusVisible = require('postcss-focus-visible');
38
39
postcss([
40
postcssFocusVisible()
41
]).process(yourCSS);
42
```
43
44
Input CSS:
45
46
```css
47
:focus:not(:focus-visible) {
48
outline: none;
49
}
50
```
51
52
Output CSS (with default options):
53
54
```css
55
:focus:not(.focus-visible).js-focus-visible, .js-focus-visible :focus:not(.focus-visible) {
56
outline: none;
57
}
58
:focus:not(:focus-visible) {
59
outline: none;
60
}
61
```
62
63
## Capabilities
64
65
### Main Plugin Function
66
67
Creates a PostCSS plugin instance with optional configuration.
68
69
```typescript { .api }
70
/**
71
* Creates a PostCSS plugin that transforms :focus-visible pseudo-selectors
72
* @param opts - Optional plugin configuration
73
* @returns PostCSS plugin instance
74
*/
75
function postcssFocusVisible(opts?: pluginOptions): PostCSS.Plugin;
76
```
77
78
The plugin automatically:
79
- Detects `:focus-visible` pseudo-classes in selectors
80
- Replaces them with configurable class selectors (default: `.focus-visible`)
81
- Adds polyfill-ready class prefixes for compatibility (default: `.js-focus-visible`)
82
- Preserves original selectors alongside transformed ones (configurable)
83
84
### Configuration Options
85
86
Plugin behavior can be customized through the options parameter.
87
88
```typescript { .api }
89
interface pluginOptions {
90
/** Preserve the original notation. default: true */
91
preserve?: boolean;
92
/** The replacement class to be used in the polyfill. default: ".focus-visible" */
93
replaceWith?: string;
94
/** Disable the selector prefix that is used to prevent a flash of incorrectly styled content. default: false */
95
disablePolyfillReadyClass?: boolean;
96
}
97
```
98
99
**preserve (boolean, default: true)**
100
- `true`: Keeps both original and transformed selectors in output
101
- `false`: Removes original selectors, leaving only transformed ones
102
103
Example with `preserve: false`:
104
105
```javascript
106
postcssFocusVisible({ preserve: false })
107
```
108
109
Input:
110
```css
111
:focus:not(:focus-visible) {
112
outline: none;
113
}
114
```
115
116
Output:
117
```css
118
:focus:not(.focus-visible).js-focus-visible, .js-focus-visible :focus:not(.focus-visible) {
119
outline: none;
120
}
121
```
122
123
**replaceWith (string, default: ".focus-visible")**
124
125
Defines the replacement selector for `:focus-visible`. Must be compatible with the focus-visible polyfill if used.
126
127
Example with custom replacement:
128
129
```javascript
130
postcssFocusVisible({ replaceWith: '[data-focus-visible-added]' })
131
```
132
133
Input:
134
```css
135
:focus:not(:focus-visible) {
136
outline: none;
137
}
138
```
139
140
Output:
141
```css
142
:focus:not([data-focus-visible-added]).js-focus-visible, .js-focus-visible :focus:not([data-focus-visible-added]) {
143
outline: none;
144
}
145
:focus:not(:focus-visible) {
146
outline: none;
147
}
148
```
149
150
**disablePolyfillReadyClass (boolean, default: false)**
151
152
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.
153
154
Example with disabled polyfill-ready class:
155
156
```javascript
157
postcssFocusVisible({ disablePolyfillReadyClass: true })
158
```
159
160
Input:
161
```css
162
:focus:not(:focus-visible) {
163
outline: none;
164
}
165
```
166
167
Output:
168
```css
169
:focus:not(.focus-visible) {
170
outline: none;
171
}
172
:focus:not(:focus-visible) {
173
outline: none;
174
}
175
```
176
177
### Plugin Properties
178
179
The plugin function includes standard PostCSS plugin properties.
180
181
```typescript { .api }
182
/**
183
* PostCSS plugin flag indicating this is a valid PostCSS plugin
184
*/
185
postcssFocusVisible.postcss: true;
186
```
187
188
## Integration Patterns
189
190
### With PostCSS CLI
191
192
```bash
193
npx postcss src/*.css --use postcss-focus-visible --dir dest
194
```
195
196
### With Webpack and postcss-loader
197
198
```javascript
199
module.exports = {
200
module: {
201
rules: [
202
{
203
test: /\.css$/,
204
use: [
205
'style-loader',
206
'css-loader',
207
{
208
loader: 'postcss-loader',
209
options: {
210
postcssOptions: {
211
plugins: [
212
require('postcss-focus-visible')()
213
]
214
}
215
}
216
}
217
]
218
}
219
]
220
}
221
};
222
```
223
224
### With PostCSS Load Config
225
226
Create a `postcss.config.js` file:
227
228
```javascript
229
module.exports = {
230
plugins: [
231
require('postcss-focus-visible')({
232
preserve: true,
233
replaceWith: '.focus-visible'
234
})
235
]
236
};
237
```
238
239
## Polyfill Integration
240
241
This plugin is designed to work with the [focus-visible polyfill](https://github.com/WICG/focus-visible). The polyfill should be included in your JavaScript bundle:
242
243
```bash
244
npm install focus-visible
245
```
246
247
```javascript
248
import 'focus-visible';
249
```
250
251
The polyfill automatically:
252
- Adds the `.js-focus-visible` class to the document when loaded
253
- Manages the `.focus-visible` class on focused elements based on focus method
254
- Provides consistent behavior across all browsers
255
256
## Error Handling
257
258
The plugin includes built-in error handling for malformed selectors:
259
260
- Invalid CSS selectors are logged as warnings and left unchanged
261
- Malformed `:focus-visible` pseudo-classes are skipped
262
- Processing continues for valid selectors even if some fail to parse
263
264
## Browser Compatibility
265
266
- **Modern browsers**: Native `:focus-visible` support (Chrome 86+, Firefox 85+, Safari 15.4+)
267
- **Legacy browsers**: Requires focus-visible polyfill for full functionality
268
- **Node.js**: Requires Node.js 18+ (as specified in package engines)
269
270
## Dependencies
271
272
- **postcss-selector-parser**: CSS selector parsing and manipulation (runtime dependency)
273
- **postcss**: PostCSS framework (peer dependency ^8.4)