or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

browser-polyfill.mdindex.mdpostcss-plugin.md

browser-polyfill.mddocs/

0

# Browser Polyfill

1

2

The browser polyfill provides `:focus-within` behavior in browsers that don't support the native pseudo-class by dynamically applying attributes or classes to elements when their descendants receive focus.

3

4

## Capabilities

5

6

### Polyfill Initialization Function

7

8

Initializes the focus-within polyfill in the browser environment. The polyfill detects browser support and only activates if needed (unless forced).

9

10

```javascript { .api }

11

/**

12

* Initialize the focus-within polyfill in the browser

13

* @param options - Polyfill configuration options

14

*/

15

function focusWithin(options?: BrowserOptions): void;

16

17

interface BrowserOptions {

18

/** Force polyfill to run even if browser supports :focus-within. Default: false */

19

force?: boolean;

20

/** The replacement selector (class or attribute). Default: "[focus-within]" */

21

replaceWith?: string;

22

}

23

```

24

25

**Usage Examples:**

26

27

```javascript

28

import focusWithin from "postcss-focus-within/browser";

29

30

// Basic initialization with default options

31

focusWithin();

32

33

// Force polyfill to run regardless of browser support

34

focusWithin({ force: true });

35

36

// Use custom replacement selector

37

focusWithin({ replaceWith: ".focus-within" });

38

39

// Combined options

40

focusWithin({

41

force: false,

42

replaceWith: "[data-focus-within]"

43

});

44

```

45

46

**Global script usage:**

47

48

Note: When using the global script, the function is available as `focusWithinInit` (not `focusWithin`).

49

50

```html

51

<script src="https://unpkg.com/postcss-focus-within@9.0.1/dist/browser-global.js"></script>

52

<script>

53

focusWithinInit({ replaceWith: "[focus-within]" });

54

</script>

55

```

56

57

### Polyfill Options

58

59

#### force

60

61

Controls whether the polyfill runs even when the browser natively supports `:focus-within`.

62

63

```javascript { .api }

64

force?: boolean; // Default: false

65

```

66

67

**Usage:**

68

69

```javascript

70

// Only run if browser lacks support (default)

71

focusWithin({ force: false });

72

73

// Always run polyfill

74

focusWithin({ force: true });

75

```

76

77

#### replaceWith

78

79

Specifies the attribute or class to apply to elements when they contain focused descendants. Must match the `replaceWith` option used in the PostCSS plugin.

80

81

```javascript { .api }

82

replaceWith?: string; // Default: "[focus-within]"

83

```

84

85

**Supported formats:**

86

87

```javascript

88

// Attribute selector (default)

89

focusWithin({ replaceWith: "[focus-within]" });

90

91

// Class selector

92

focusWithin({ replaceWith: ".focus-within" });

93

94

// Custom attribute

95

focusWithin({ replaceWith: "[data-focus]" });

96

```

97

98

### Polyfill Behavior

99

100

#### Automatic Browser Detection

101

102

The polyfill automatically detects browser support by attempting to use `document.querySelector(':focus-within')`. If this throws an error, the polyfill activates.

103

104

```javascript

105

try {

106

document.querySelector(':focus-within');

107

// Browser supports :focus-within, polyfill won't run (unless forced)

108

} catch (error) {

109

// Browser doesn't support :focus-within, polyfill will run

110

}

111

```

112

113

#### DOM Ready Handling

114

115

The polyfill handles various document ready states:

116

117

```javascript

118

if (document.readyState === 'complete') {

119

// Initialize immediately

120

} else {

121

// Wait for DOMContentLoaded event

122

document.addEventListener('DOMContentLoaded', initialize);

123

}

124

```

125

126

#### Focus Event Management

127

128

The polyfill manages focus state by listening to focus and blur events:

129

130

```javascript

131

// Event listeners are attached with capture: true

132

document.addEventListener('focus', handleFocusChange, true);

133

document.addEventListener('blur', handleFocusChange, true);

134

```

135

136

#### Element State Management

137

138

When focus changes, the polyfill:

139

140

1. Removes the replacement selector from all previously focused ancestor elements

141

2. Identifies the currently focused element

142

3. Applies the replacement selector to the focused element and all its ancestors (excluding document, HTML, and BODY)

143

144

**Example behavior:**

145

146

```html

147

<!-- Before focus -->

148

<form class="my-form">

149

<fieldset class="fieldset">

150

<input type="text" id="name">

151

</fieldset>

152

</form>

153

154

<!-- After focusing input with replaceWith: "[focus-within]" -->

155

<form class="my-form" focus-within>

156

<fieldset class="fieldset" focus-within>

157

<input type="text" id="name">

158

</fieldset>

159

</form>

160

```

161

162

#### Polyfill Ready Class

163

164

The polyfill automatically adds the `js-focus-within` class to the document element to indicate it's active:

165

166

```javascript

167

document.documentElement.className += ' js-focus-within';

168

```

169

170

This class is used by the PostCSS plugin to scope fallback selectors and prevent flash of unstyled content.

171

172

### Error Handling

173

174

The polyfill validates the `replaceWith` option and throws an error for invalid selectors:

175

176

```javascript

177

// These will throw errors:

178

focusWithin({ replaceWith: ".class > .child" }); // Contains >

179

focusWithin({ replaceWith: "[attr]:hover" }); // Contains :

180

focusWithin({ replaceWith: "#id" }); // Contains #

181

```

182

183

**Error example:**

184

185

```javascript

186

try {

187

focusWithin({ replaceWith: "#invalid" });

188

} catch (error) {

189

console.error(error.message);

190

// "#invalid is not a valid replacement since it can't be applied to single elements."

191

}

192

```

193

194

### Framework Integration

195

196

#### Next.js Integration

197

198

For Next.js applications, use dynamic imports to ensure the polyfill only runs in the browser:

199

200

```javascript

201

import { useEffect } from 'react';

202

203

useEffect(async () => {

204

const focusWithin = (await import('postcss-focus-within/browser')).default;

205

focusWithin();

206

}, []);

207

```