or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Resize Observer Polyfill

1

2

A polyfill for the Resize Observer API that enables developers to observe changes to the dimensions of DOM elements. This polyfill uses MutationObserver as the primary strategy with Mutation Events as a fallback for older browsers, avoiding polling mechanisms while maintaining performance.

3

4

## Package Information

5

6

- **Package Name**: resize-observer-polyfill

7

- **Package Type**: npm

8

- **Language**: JavaScript/TypeScript

9

- **Installation**: `npm install resize-observer-polyfill`

10

11

## Core Imports

12

13

```javascript

14

import ResizeObserver from 'resize-observer-polyfill';

15

```

16

17

For CommonJS:

18

19

```javascript

20

const ResizeObserver = require('resize-observer-polyfill');

21

```

22

23

For UMD (browser globals):

24

25

```html

26

<script src="./node_modules/resize-observer-polyfill/dist/ResizeObserver.js"></script>

27

<!-- ResizeObserver is now available globally -->

28

```

29

30

## Basic Usage

31

32

```javascript

33

import ResizeObserver from 'resize-observer-polyfill';

34

35

// Create a ResizeObserver instance

36

const resizeObserver = new ResizeObserver((entries, observer) => {

37

for (const entry of entries) {

38

const { left, top, width, height } = entry.contentRect;

39

40

console.log('Element:', entry.target);

41

console.log(`Element's size: ${width}px x ${height}px`);

42

console.log(`Element's paddings: ${top}px ; ${left}px`);

43

}

44

});

45

46

// Start observing an element

47

resizeObserver.observe(document.body);

48

49

// Stop observing a specific element

50

resizeObserver.unobserve(document.body);

51

52

// Stop observing all elements

53

resizeObserver.disconnect();

54

```

55

56

## Architecture

57

58

The polyfill implements the official ResizeObserver specification and follows these key principles:

59

60

- **Ponyfill Design**: Doesn't modify global objects unless needed

61

- **Fallback Strategy**: Uses MutationObserver primarily, with Mutation Events fallback for IE9-10

62

- **Performance Optimization**: Batches and throttles updates with ~20ms delay

63

- **Spec Compliance**: Follows the W3C ResizeObserver specification exactly

64

- **Browser Compatibility**: Supports IE9+ through modern browsers

65

66

## Capabilities

67

68

### ResizeObserver Constructor

69

70

Creates a new ResizeObserver instance that can observe element size changes.

71

72

```typescript { .api }

73

/**

74

* Creates a new ResizeObserver instance

75

* @param callback - Function called when observed elements change size

76

*/

77

constructor(callback: ResizeObserverCallback): ResizeObserver;

78

79

interface ResizeObserverCallback {

80

(entries: ResizeObserverEntry[], observer: ResizeObserver): void;

81

}

82

```

83

84

**Usage Example:**

85

86

```javascript

87

const observer = new ResizeObserver((entries, observer) => {

88

entries.forEach(entry => {

89

console.log('Size changed:', entry.contentRect);

90

});

91

});

92

```

93

94

### Element Observation

95

96

Methods for managing which elements are being observed for size changes.

97

98

```typescript { .api }

99

/**

100

* Begin observing size changes for the specified element

101

* @param target - DOM element to observe

102

*/

103

observe(target: Element): void;

104

105

/**

106

* Stop observing size changes for the specified element

107

* @param target - DOM element to stop observing

108

*/

109

unobserve(target: Element): void;

110

111

/**

112

* Stop observing all currently observed elements

113

*/

114

disconnect(): void;

115

```

116

117

**Usage Examples:**

118

119

```javascript

120

// Start observing multiple elements

121

observer.observe(document.getElementById('sidebar'));

122

observer.observe(document.querySelector('.main-content'));

123

124

// Stop observing a specific element

125

observer.unobserve(document.getElementById('sidebar'));

126

127

// Stop all observations

128

observer.disconnect();

129

```

130

131

### ResizeObserver Entry Data

132

133

The data structure provided to the callback function for each observed element.

134

135

```typescript { .api }

136

interface ResizeObserverEntry {

137

/** The observed element that changed size */

138

readonly target: Element;

139

/** The element's content rectangle with size information */

140

readonly contentRect: DOMRectReadOnly;

141

}

142

143

interface DOMRectReadOnly {

144

/** X coordinate of the rectangle */

145

readonly x: number;

146

/** Y coordinate of the rectangle */

147

readonly y: number;

148

/** Width of the rectangle */

149

readonly width: number;

150

/** Height of the rectangle */

151

readonly height: number;

152

/** Distance from top edge to element's top padding edge */

153

readonly top: number;

154

/** Distance from left edge to element's right padding edge */

155

readonly right: number;

156

/** Distance from top edge to element's bottom padding edge */

157

readonly bottom: number;

158

/** Distance from left edge to element's left padding edge */

159

readonly left: number;

160

}

161

```

162

163

**Usage Example:**

164

165

```javascript

166

const observer = new ResizeObserver((entries) => {

167

entries.forEach(entry => {

168

const { target, contentRect } = entry;

169

const { width, height, top, left } = contentRect;

170

171

// Update element based on its new size

172

if (width < 300) {

173

target.classList.add('compact');

174

} else {

175

target.classList.remove('compact');

176

}

177

178

console.log(`${target.tagName} is now ${width}x${height}`);

179

});

180

});

181

```

182

183

## Advanced Usage Patterns

184

185

### Responsive Component Behavior

186

187

```javascript

188

import ResizeObserver from 'resize-observer-polyfill';

189

190

class ResponsiveComponent {

191

constructor(element) {

192

this.element = element;

193

this.observer = new ResizeObserver(this.handleResize.bind(this));

194

this.observer.observe(element);

195

}

196

197

handleResize(entries) {

198

const entry = entries[0];

199

const { width } = entry.contentRect;

200

201

// Apply different layouts based on width

202

if (width < 480) {

203

this.element.className = 'component mobile';

204

} else if (width < 768) {

205

this.element.className = 'component tablet';

206

} else {

207

this.element.className = 'component desktop';

208

}

209

}

210

211

destroy() {

212

this.observer.disconnect();

213

}

214

}

215

```

216

217

### Container Query Simulation

218

219

```javascript

220

import ResizeObserver from 'resize-observer-polyfill';

221

222

function setupContainerQueries() {

223

const containers = document.querySelectorAll('[data-container-query]');

224

225

const observer = new ResizeObserver((entries) => {

226

entries.forEach(entry => {

227

const { target, contentRect } = entry;

228

const { width } = contentRect;

229

230

// Remove existing size classes

231

target.classList.remove('sm', 'md', 'lg', 'xl');

232

233

// Add appropriate size class

234

if (width >= 1200) {

235

target.classList.add('xl');

236

} else if (width >= 992) {

237

target.classList.add('lg');

238

} else if (width >= 768) {

239

target.classList.add('md');

240

} else {

241

target.classList.add('sm');

242

}

243

});

244

});

245

246

containers.forEach(container => observer.observe(container));

247

248

return observer;

249

}

250

```

251

252

## Browser Support and Limitations

253

254

### Supported Browsers

255

- Chrome, Firefox, Safari, Edge (modern versions)

256

- Internet Explorer 9+

257

- Mobile browsers (iOS Safari, Chrome Mobile, etc.)

258

259

### Known Limitations

260

- Notifications are delivered ~20ms after actual changes happen

261

- Changes caused by dynamic pseudo-classes (`:hover`, `:focus`) are not tracked

262

- Delayed transitions receive only one notification with final dimensions

263

264

### Workaround for Pseudo-class Changes

265

266

```javascript

267

// Add a short transition to trigger transitionend events

268

.element:hover {

269

transition: opacity 0.001s;

270

}

271

```

272

273

## TypeScript Support

274

275

The package includes full TypeScript definitions:

276

277

```typescript

278

import ResizeObserver from 'resize-observer-polyfill';

279

280

const observer: ResizeObserver = new ResizeObserver(

281

(entries: ResizeObserverEntry[], observer: ResizeObserver) => {

282

entries.forEach((entry: ResizeObserverEntry) => {

283

const rect: DOMRectReadOnly = entry.contentRect;

284

console.log(`Size: ${rect.width}x${rect.height}`);

285

});

286

}

287

);

288

```

289

290

## Error Handling

291

292

The ResizeObserver follows the same error handling as the native implementation:

293

294

```javascript

295

const observer = new ResizeObserver((entries) => {

296

// Callback errors don't break the observer

297

entries.forEach(entry => {

298

try {

299

processEntry(entry);

300

} catch (error) {

301

console.error('Error processing resize entry:', error);

302

}

303

});

304

});

305

306

// Constructor validates arguments

307

try {

308

new ResizeObserver(); // Throws TypeError

309

} catch (error) {

310

console.error(error.message); // "1 argument required, but only 0 present."

311

}

312

313

try {

314

new ResizeObserver.call(null, () => {}); // Throws TypeError

315

} catch (error) {

316

console.error(error.message); // "Cannot call a class as a function."

317

}

318

```