or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Storybook Addon Measure

1

2

Storybook Addon Measure is a visual measurement and box model inspection tool for Storybook that enables developers to inspect layouts and visualize CSS box models by hovering over DOM elements and pressing keyboard shortcuts.

3

4

**⚠️ DEPRECATION NOTICE**: This package is deprecated in Storybook 9.0+. The functionality has been moved to the core Storybook package and is now available by default without requiring separate installation.

5

6

## Package Information

7

8

- **Package Name**: @storybook/addon-measure

9

- **Package Type**: npm

10

- **Language**: TypeScript

11

- **Installation**: `npm install @storybook/addon-measure` (deprecated - throws error in v9.0+)

12

- **Migration**: Remove from dependencies - functionality included in Storybook 9.0+ core

13

14

## Core Imports

15

16

**Deprecated package (v9.0+):**

17

18

```typescript

19

// These imports throw migration errors in v9.0+:

20

// Error: Your Storybook project is referring to package @storybook/addon-measure,

21

// which no longer exists in Storybook 9.0 and above.

22

import { withMeasure } from "@storybook/addon-measure";

23

```

24

25

**Current usage (Storybook 9.0+ core):**

26

27

```typescript

28

// Functionality is now available automatically in Storybook core

29

// No imports needed - the measure decorator is included automatically when FEATURES.measure is enabled

30

// Access through Storybook's internal APIs if needed for custom implementation:

31

import { useGlobals } from 'storybook/manager-api';

32

import type { MeasureParameters } from 'storybook/internal/types';

33

```

34

35

## Basic Usage

36

37

**Legacy usage (pre-v9.0):**

38

39

```typescript

40

// In .storybook/main.js - NO LONGER WORKS

41

export default {

42

addons: ['@storybook/addon-measure'], // This will cause errors in v9.0+

43

};

44

```

45

46

**Current usage (v9.0+):**

47

48

```typescript

49

// No configuration needed - measure is included in core automatically

50

// Usage:

51

// 1. Press 'M' key to enable measurement mode (or click the ruler icon in toolbar)

52

// 2. Hover over any DOM element in your story

53

// 3. View margin, padding, border, and content dimensions with color-coded overlays

54

55

// To disable measure for specific stories:

56

export default {

57

parameters: {

58

measure: {

59

disable: true, // Disable measure for this component/story

60

},

61

},

62

};

63

```

64

65

## Architecture

66

67

The measure system (now part of Storybook core) consists of several key components:

68

69

- **Feature Flag System**: Controlled by `globalThis.FEATURES?.measure` flag in Storybook core

70

- **Decorator System**: React decorator (`withMeasure`) automatically included when feature is enabled

71

- **Canvas Overlay**: HTML5 canvas element overlaying the story viewport for drawing measurements

72

- **Event Handling**: Mouse tracking (`pointermove`, `pointerover`) and keyboard shortcut integration

73

- **Measurement Engine**: CSS computed style analysis and box model calculation using `getComputedStyle`

74

- **Visualization System**: Color-coded overlay rendering with intelligent label positioning and collision detection

75

- **Shadow DOM Support**: Deep element traversal including web components via `crawlShadows`

76

- **Manager Integration**: Toolbar button and keyboard shortcut registration through Storybook's addon system

77

78

## Capabilities

79

80

### Measurement Activation

81

82

Control when measurement mode is active through global state and keyboard shortcuts.

83

84

```typescript { .api }

85

/**

86

* Global state key for controlling measurement mode

87

*/

88

const PARAM_KEY = 'measureEnabled';

89

90

/**

91

* Addon and tool identifiers

92

*/

93

const ADDON_ID = 'storybook/measure-addon';

94

const TOOL_ID = 'storybook/measure-addon/tool';

95

```

96

97

### Decorator Function

98

99

React decorator that adds measurement capability to Storybook stories (automatically included in core).

100

101

```typescript { .api }

102

/**

103

* React decorator for adding measurement functionality to stories

104

* Automatically registered when globalThis.FEATURES?.measure is enabled

105

* @param StoryFn - The story component function

106

* @param context - Storybook story context with globals and viewMode

107

* @returns Story component with measurement capabilities

108

*/

109

const withMeasure: DecoratorFunction<StoryContext> = (StoryFn, context) => React.ReactElement;

110

111

interface StoryContext {

112

globals: {

113

measureEnabled?: boolean;

114

};

115

viewMode: 'story' | 'canvas' | 'docs';

116

parameters: {

117

measure?: MeasureParameters['measure'];

118

};

119

}

120

```

121

122

### Canvas Management

123

124

HTML5 canvas overlay system for rendering measurements.

125

126

```typescript { .api }

127

/**

128

* Initialize measurement canvas overlay

129

*/

130

function init(): void;

131

132

/**

133

* Clear all drawn measurements from canvas

134

*/

135

function clear(): void;

136

137

/**

138

* Execute drawing operations with automatic clear

139

* @param callback - Drawing function receiving canvas context

140

*/

141

function draw(callback: (context?: CanvasRenderingContext2D) => void): void;

142

143

/**

144

* Rescale canvas for viewport changes

145

*/

146

function rescale(): void;

147

148

/**

149

* Remove canvas overlay and cleanup resources

150

*/

151

function destroy(): void;

152

```

153

154

### Element Measurement

155

156

Core measurement analysis and DOM element inspection.

157

158

```typescript { .api }

159

/**

160

* Get DOM element at coordinates with shadow DOM support

161

* Crawls through shadow DOM boundaries to find the deepest element

162

* @param x - X coordinate in pixels

163

* @param y - Y coordinate in pixels

164

* @returns HTML element at the specified coordinates

165

*/

166

function deepElementFromPoint(x: number, y: number): HTMLElement;

167

168

/**

169

* Draw box model measurements for specified element

170

* @param element - HTML element to measure and visualize

171

*/

172

function drawSelectedElement(element: HTMLElement): void;

173

174

/**

175

* Measure element dimensions and calculate box model values

176

* @param element - HTML element to measure

177

* @returns Complete measurement data including box model and positioning

178

*/

179

function measureElement(element: HTMLElement): ElementMeasurements;

180

181

/**

182

* Internal function to crawl shadow DOM boundaries

183

* @param node - HTML element that may contain shadow DOM

184

* @returns Deepest accessible element in shadow DOM tree

185

*/

186

function crawlShadows(node: HTMLElement): HTMLElement;

187

```

188

189

### Manager UI Integration

190

191

Storybook manager panel integration for measurement controls.

192

193

```typescript { .api }

194

/**

195

* Register measurement tool in Storybook manager

196

* Only registers if globalThis.FEATURES?.measure is enabled

197

*/

198

function default(): void;

199

200

/**

201

* React component for measurement toggle button with ruler icon

202

* Uses useGlobals hook to manage measureEnabled state

203

*/

204

const Tool: React.FC = () => React.ReactElement;

205

206

/**

207

* Addon registration configuration

208

*/

209

interface AddonConfig {

210

type: 'TOOL';

211

title: 'Measure';

212

match: (args: { viewMode: string; tabId?: string }) => boolean;

213

render: () => React.ReactElement;

214

}

215

216

/**

217

* Keyboard shortcut configuration object passed to setAddonShortcut

218

*/

219

interface ShortcutConfig {

220

label: 'Toggle Measure [M]';

221

defaultShortcut: ['M'];

222

actionName: 'measure';

223

showInMenu: false;

224

action: () => void;

225

}

226

227

/**

228

* Hook for accessing and updating global measure state

229

* @returns Tuple of [globals, updateGlobals] for measure control

230

*/

231

function useGlobals(): [{ measureEnabled?: boolean }, (globals: any) => void];

232

```

233

234

### Configuration Interface

235

236

Parameter interface for controlling measurement behavior.

237

238

```typescript { .api }

239

/**

240

* Configuration parameters for measurement addon

241

*/

242

interface MeasureParameters {

243

measure: {

244

/** Remove the addon panel and disable the addon's behavior */

245

disable?: boolean;

246

};

247

}

248

```

249

250

## Types

251

252

### Measurement Data Types

253

254

```typescript { .api }

255

/**

256

* Margin measurements in pixels

257

*/

258

interface Margin {

259

top: number;

260

bottom: number;

261

left: number;

262

right: number;

263

}

264

265

/**

266

* Padding measurements in pixels

267

*/

268

interface Padding {

269

top: number;

270

bottom: number;

271

left: number;

272

right: number;

273

}

274

275

/**

276

* Border measurements in pixels

277

*/

278

interface Border {

279

top: number;

280

bottom: number;

281

left: number;

282

right: number;

283

}

284

285

/**

286

* Complete box model dimensions

287

*/

288

interface Dimensions {

289

margin: Margin;

290

padding: Padding;

291

border: Border;

292

width: number;

293

height: number;

294

top: number;

295

left: number;

296

bottom: number;

297

right: number;

298

}

299

300

/**

301

* Element boundary coordinates

302

*/

303

interface Extremities {

304

top: number;

305

bottom: number;

306

left: number;

307

right: number;

308

}

309

310

/**

311

* Label positioning alignment

312

*/

313

interface FloatingAlignment {

314

x: 'left' | 'right';

315

y: 'top' | 'bottom';

316

}

317

318

/**

319

* Complete element measurement data

320

*/

321

interface ElementMeasurements extends Dimensions {

322

extremities: Extremities;

323

floatingAlignment: FloatingAlignment;

324

}

325

```

326

327

### Label System Types

328

329

```typescript { .api }

330

/**

331

* Label type categories

332

*/

333

type LabelType = 'margin' | 'padding' | 'border' | 'content';

334

335

/**

336

* Label positioning options

337

*/

338

type LabelPosition = 'top' | 'right' | 'bottom' | 'left' | 'center';

339

340

/**

341

* Direction for measurements

342

*/

343

type Direction = 'top' | 'right' | 'bottom' | 'left';

344

345

/**

346

* Individual measurement label

347

*/

348

interface Label {

349

type: LabelType;

350

text: number | string;

351

position: LabelPosition;

352

}

353

354

/**

355

* Collection of labels for rendering

356

*/

357

type LabelStack = Label[];

358

359

/**

360

* Canvas drawing utilities

361

*/

362

interface RectSize {

363

w: number;

364

h: number;

365

}

366

367

interface Coordinate {

368

x: number;

369

y: number;

370

}

371

372

interface Rect extends RectSize, Coordinate {}

373

374

interface RoundedRect extends Rect {

375

r: number;

376

}

377

```

378

379

### Event System

380

381

```typescript { .api }

382

/**

383

* Addon event identifiers

384

*/

385

const EVENTS = {

386

RESULT: 'storybook/measure-addon/result';

387

REQUEST: 'storybook/measure-addon/request';

388

CLEAR: 'storybook/measure-addon/clear';

389

};

390

391

/**

392

* Addon identifiers

393

*/

394

const ADDON_ID = 'storybook/measure-addon';

395

const TOOL_ID = 'storybook/measure-addon/tool';

396

```

397

398

## Visual Features

399

400

### Box Model Visualization

401

402

- **Margin**: Semi-transparent orange overlay (`#f6b26ba8`)

403

- **Border**: Semi-transparent yellow overlay (`#ffe599a8`)

404

- **Padding**: Semi-transparent green overlay (`#93c47d8c`)

405

- **Content**: Semi-transparent blue overlay (`#6fa8dca8`)

406

407

### Smart Labeling

408

409

- **Collision Detection**: Labels automatically reposition to avoid overlaps using `filterZeroValues`

410

- **External Positioning**: Small elements (< 30px) show labels outside the element bounds

411

- **Floating Labels**: Content dimensions displayed as floating labels with intelligent alignment

412

- **Color Coding**: Labels use matching colors - margin (`#f6b26b`), border (`#ffe599`), padding (`#93c47d`), content (`#6fa8dc`)

413

- **Rounded Label Backgrounds**: Labels rendered with rounded rectangles and 6px padding

414

415

### Responsive Behavior

416

417

- **Auto-scaling**: Canvas automatically rescales on window resize using `devicePixelRatio`

418

- **High DPI Support**: Proper scaling for high-density displays with context scaling

419

- **Pointer Tracking**: Real-time mouse position tracking with `requestAnimationFrame` optimization

420

- **Shadow DOM**: Deep traversal into Shadow DOM boundaries via recursive `crawlShadows`

421

- **Performance Optimization**: Uses `pointerover` events rather than continuous `mousemove` for better performance

422

- **Canvas Management**: Dynamic canvas creation with proper z-index (`2147483647`) and pointer-events disabled

423

424

### Utility Functions

425

426

Additional internal utility functions used in the measurement system.

427

428

```typescript { .api }

429

/**

430

* Convert CSS pixel string to number

431

* @param px - CSS pixel value (e.g., "16px")

432

* @returns Numeric pixel value

433

*/

434

function pxToNumber(px: string): number;

435

436

/**

437

* Round number to appropriate precision

438

* @param value - Number to round

439

* @returns Integer if whole number, otherwise 2 decimal places

440

*/

441

function round(value: number): number | string;

442

443

/**

444

* Remove zero-value labels from label stack

445

* @param labels - Array of labels to filter

446

* @returns Filtered labels without zero values

447

*/

448

function filterZeroValues(labels: LabelStack): LabelStack;

449

450

/**

451

* Calculate optimal floating label alignment

452

* @param extremities - Element boundary coordinates

453

* @returns Alignment configuration for label positioning

454

*/

455

function floatingAlignment(extremities: Extremities): FloatingAlignment;

456

457

/**

458

* Get document dimensions including scroll areas

459

* @returns Width and height of the full document

460

*/

461

function getDocumentWidthAndHeight(): { width: number; height: number };

462

```

463

464

## Migration Guide

465

466

For projects upgrading to Storybook 9.0+:

467

468

1. **Remove the addon**: Delete `@storybook/addon-measure` from `package.json` dependencies

469

2. **Update configuration**: Remove `@storybook/addon-measure` from `.storybook/main.js` addons array

470

3. **Handle errors**: The old package now throws descriptive migration errors when imported

471

4. **No code changes**: Measurement functionality works identically with same keyboard shortcuts

472

5. **Feature flag**: Ensure `FEATURES.measure` is enabled in your Storybook configuration (enabled by default)

473

6. **Keyboard shortcut**: Continue using 'M' key or ruler toolbar button to toggle measurements

474

475

**Migration example:**

476

477

```diff

478

// .storybook/main.js

479

export default {

480

addons: [

481

- '@storybook/addon-measure',

482

'@storybook/addon-essentials',

483

// measure is now included automatically in core

484

],

485

};

486

```

487

488

```diff

489

// package.json

490

{

491

"devDependencies": {

492

- "@storybook/addon-measure": "^8.x.x",

493

"@storybook/react": "^9.0.0"

494

}

495

}

496

```

497

498

The core functionality remains unchanged - only the installation and configuration requirements have been removed. All API functions are now internal to Storybook core.