Visual measurement and box model inspection tool for Storybook development (deprecated in v9.0+)
npx @tessl/cli install tessl/npm-storybook--addon-measure@9.0.0Storybook 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.
⚠️ 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.
npm install @storybook/addon-measure (deprecated - throws error in v9.0+)Deprecated package (v9.0+):
// These imports throw migration errors in v9.0+:
// Error: Your Storybook project is referring to package @storybook/addon-measure,
// which no longer exists in Storybook 9.0 and above.
import { withMeasure } from "@storybook/addon-measure";Current usage (Storybook 9.0+ core):
// Functionality is now available automatically in Storybook core
// No imports needed - the measure decorator is included automatically when FEATURES.measure is enabled
// Access through Storybook's internal APIs if needed for custom implementation:
import { useGlobals } from 'storybook/manager-api';
import type { MeasureParameters } from 'storybook/internal/types';Legacy usage (pre-v9.0):
// In .storybook/main.js - NO LONGER WORKS
export default {
addons: ['@storybook/addon-measure'], // This will cause errors in v9.0+
};Current usage (v9.0+):
// No configuration needed - measure is included in core automatically
// Usage:
// 1. Press 'M' key to enable measurement mode (or click the ruler icon in toolbar)
// 2. Hover over any DOM element in your story
// 3. View margin, padding, border, and content dimensions with color-coded overlays
// To disable measure for specific stories:
export default {
parameters: {
measure: {
disable: true, // Disable measure for this component/story
},
},
};The measure system (now part of Storybook core) consists of several key components:
globalThis.FEATURES?.measure flag in Storybook corewithMeasure) automatically included when feature is enabledpointermove, pointerover) and keyboard shortcut integrationgetComputedStylecrawlShadowsControl when measurement mode is active through global state and keyboard shortcuts.
/**
* Global state key for controlling measurement mode
*/
const PARAM_KEY = 'measureEnabled';
/**
* Addon and tool identifiers
*/
const ADDON_ID = 'storybook/measure-addon';
const TOOL_ID = 'storybook/measure-addon/tool';React decorator that adds measurement capability to Storybook stories (automatically included in core).
/**
* React decorator for adding measurement functionality to stories
* Automatically registered when globalThis.FEATURES?.measure is enabled
* @param StoryFn - The story component function
* @param context - Storybook story context with globals and viewMode
* @returns Story component with measurement capabilities
*/
const withMeasure: DecoratorFunction<StoryContext> = (StoryFn, context) => React.ReactElement;
interface StoryContext {
globals: {
measureEnabled?: boolean;
};
viewMode: 'story' | 'canvas' | 'docs';
parameters: {
measure?: MeasureParameters['measure'];
};
}HTML5 canvas overlay system for rendering measurements.
/**
* Initialize measurement canvas overlay
*/
function init(): void;
/**
* Clear all drawn measurements from canvas
*/
function clear(): void;
/**
* Execute drawing operations with automatic clear
* @param callback - Drawing function receiving canvas context
*/
function draw(callback: (context?: CanvasRenderingContext2D) => void): void;
/**
* Rescale canvas for viewport changes
*/
function rescale(): void;
/**
* Remove canvas overlay and cleanup resources
*/
function destroy(): void;Core measurement analysis and DOM element inspection.
/**
* Get DOM element at coordinates with shadow DOM support
* Crawls through shadow DOM boundaries to find the deepest element
* @param x - X coordinate in pixels
* @param y - Y coordinate in pixels
* @returns HTML element at the specified coordinates
*/
function deepElementFromPoint(x: number, y: number): HTMLElement;
/**
* Draw box model measurements for specified element
* @param element - HTML element to measure and visualize
*/
function drawSelectedElement(element: HTMLElement): void;
/**
* Measure element dimensions and calculate box model values
* @param element - HTML element to measure
* @returns Complete measurement data including box model and positioning
*/
function measureElement(element: HTMLElement): ElementMeasurements;
/**
* Internal function to crawl shadow DOM boundaries
* @param node - HTML element that may contain shadow DOM
* @returns Deepest accessible element in shadow DOM tree
*/
function crawlShadows(node: HTMLElement): HTMLElement;Storybook manager panel integration for measurement controls.
/**
* Register measurement tool in Storybook manager
* Only registers if globalThis.FEATURES?.measure is enabled
*/
function default(): void;
/**
* React component for measurement toggle button with ruler icon
* Uses useGlobals hook to manage measureEnabled state
*/
const Tool: React.FC = () => React.ReactElement;
/**
* Addon registration configuration
*/
interface AddonConfig {
type: 'TOOL';
title: 'Measure';
match: (args: { viewMode: string; tabId?: string }) => boolean;
render: () => React.ReactElement;
}
/**
* Keyboard shortcut configuration object passed to setAddonShortcut
*/
interface ShortcutConfig {
label: 'Toggle Measure [M]';
defaultShortcut: ['M'];
actionName: 'measure';
showInMenu: false;
action: () => void;
}
/**
* Hook for accessing and updating global measure state
* @returns Tuple of [globals, updateGlobals] for measure control
*/
function useGlobals(): [{ measureEnabled?: boolean }, (globals: any) => void];Parameter interface for controlling measurement behavior.
/**
* Configuration parameters for measurement addon
*/
interface MeasureParameters {
measure: {
/** Remove the addon panel and disable the addon's behavior */
disable?: boolean;
};
}/**
* Margin measurements in pixels
*/
interface Margin {
top: number;
bottom: number;
left: number;
right: number;
}
/**
* Padding measurements in pixels
*/
interface Padding {
top: number;
bottom: number;
left: number;
right: number;
}
/**
* Border measurements in pixels
*/
interface Border {
top: number;
bottom: number;
left: number;
right: number;
}
/**
* Complete box model dimensions
*/
interface Dimensions {
margin: Margin;
padding: Padding;
border: Border;
width: number;
height: number;
top: number;
left: number;
bottom: number;
right: number;
}
/**
* Element boundary coordinates
*/
interface Extremities {
top: number;
bottom: number;
left: number;
right: number;
}
/**
* Label positioning alignment
*/
interface FloatingAlignment {
x: 'left' | 'right';
y: 'top' | 'bottom';
}
/**
* Complete element measurement data
*/
interface ElementMeasurements extends Dimensions {
extremities: Extremities;
floatingAlignment: FloatingAlignment;
}/**
* Label type categories
*/
type LabelType = 'margin' | 'padding' | 'border' | 'content';
/**
* Label positioning options
*/
type LabelPosition = 'top' | 'right' | 'bottom' | 'left' | 'center';
/**
* Direction for measurements
*/
type Direction = 'top' | 'right' | 'bottom' | 'left';
/**
* Individual measurement label
*/
interface Label {
type: LabelType;
text: number | string;
position: LabelPosition;
}
/**
* Collection of labels for rendering
*/
type LabelStack = Label[];
/**
* Canvas drawing utilities
*/
interface RectSize {
w: number;
h: number;
}
interface Coordinate {
x: number;
y: number;
}
interface Rect extends RectSize, Coordinate {}
interface RoundedRect extends Rect {
r: number;
}/**
* Addon event identifiers
*/
const EVENTS = {
RESULT: 'storybook/measure-addon/result';
REQUEST: 'storybook/measure-addon/request';
CLEAR: 'storybook/measure-addon/clear';
};
/**
* Addon identifiers
*/
const ADDON_ID = 'storybook/measure-addon';
const TOOL_ID = 'storybook/measure-addon/tool';#f6b26ba8)#ffe599a8)#93c47d8c)#6fa8dca8)filterZeroValues#f6b26b), border (#ffe599), padding (#93c47d), content (#6fa8dc)devicePixelRatiorequestAnimationFrame optimizationcrawlShadowspointerover events rather than continuous mousemove for better performance2147483647) and pointer-events disabledAdditional internal utility functions used in the measurement system.
/**
* Convert CSS pixel string to number
* @param px - CSS pixel value (e.g., "16px")
* @returns Numeric pixel value
*/
function pxToNumber(px: string): number;
/**
* Round number to appropriate precision
* @param value - Number to round
* @returns Integer if whole number, otherwise 2 decimal places
*/
function round(value: number): number | string;
/**
* Remove zero-value labels from label stack
* @param labels - Array of labels to filter
* @returns Filtered labels without zero values
*/
function filterZeroValues(labels: LabelStack): LabelStack;
/**
* Calculate optimal floating label alignment
* @param extremities - Element boundary coordinates
* @returns Alignment configuration for label positioning
*/
function floatingAlignment(extremities: Extremities): FloatingAlignment;
/**
* Get document dimensions including scroll areas
* @returns Width and height of the full document
*/
function getDocumentWidthAndHeight(): { width: number; height: number };For projects upgrading to Storybook 9.0+:
@storybook/addon-measure from package.json dependencies@storybook/addon-measure from .storybook/main.js addons arrayFEATURES.measure is enabled in your Storybook configuration (enabled by default)Migration example:
// .storybook/main.js
export default {
addons: [
- '@storybook/addon-measure',
'@storybook/addon-essentials',
// measure is now included automatically in core
],
};// package.json
{
"devDependencies": {
- "@storybook/addon-measure": "^8.x.x",
"@storybook/react": "^9.0.0"
}
}The core functionality remains unchanged - only the installation and configuration requirements have been removed. All API functions are now internal to Storybook core.