mrkeyoor.com_
Sat 08 Aug 20:59 UTC
npmWeb Frontendupdated 08 Aug 2026

css-box-model

css-box-model is a small browser utility that turns an element's bounding rectangle and computed CSS into named margin, border, padding, and content rectangles. Unlike getBoundingClientRect(), which gives only the border box, its getBox() result includes coordinates, dimensions, centers, and the four edge widths for every layer. It also exposes pure geometry helpers, so drag-and-drop and positioning code can adjust rectangles without repeatedly reading layout from the DOM.

Verdict

A focused and pleasant geometry helper for old or existing drag-and-drop code, with an API small enough to audit. For a new app that needs only one rectangle, use the DOM directly; for full placement behavior, use Floating UI.

API stability5/5The exported surface is only getBox, calculateBox, createBox, getRect, expand, shrink, offset, and withScroll, and version 1.2.1 has remained the latest release since April 2020. The declaration file mirrors those functions and their BoxModel, Rect, Position, and Spacing shapes, so consumers face very little moving API surface.
Docs3/5The README explains the four CSS box layers, prints the returned types, and includes examples for every public helper except offset. That is enough to start quickly, but it does not document browser support, layout-performance costs, server rendering, or the source behavior that turns non-pixel computed values into zero; one calculateBox sample also contains the getComputedStyles typo.
Maintenance2/5The package is not marked deprecated and the GitHub repository is not archived, but npm version 1.2.1 dates to April 2020 and GitHub reports the last push in January 2023. The repository currently shows 15 open issues and pull requests together. This looks like a finished utility receiving little attention, not an actively evolving dependency.
Ecosystem4/5The npm download endpoint reports 5,245,346 downloads for the measured week, largely because the utility sits under established drag-and-drop packages. It ships CommonJS and ES module builds plus Flow and TypeScript declarations. The scope is intentionally narrow, though, and its 170 GitHub stars and tiny public API do not imply a broad plugin ecosystem.

Use it if

  • You are writing drag-and-drop, collision, or positioning logic that repeatedly needs all four CSS box layers
  • You want one clearly named result instead of combining getBoundingClientRect() with a dozen getComputedStyle() properties
  • You already have a DOMRect and CSSStyleDeclaration and want to calculate the remaining rectangles once
  • You need pure helpers for expanding, shrinking, or offsetting rectangle-like objects
Skip it if

Setup reality

Installation is just npm install css-box-model. Version 1.2.1 has one runtime dependency, tiny-invariant, and ships CommonJS, ES module, Flow, and declaration-file entry points. There are no peer dependencies, build tools, credentials, or configuration files. The important setup constraint is the runtime: getBox() calls Element.getBoundingClientRect() and window.getComputedStyle(), while withScroll() reads window.pageXOffset and window.pageYOffset when no scroll value is passed. Keep those calls in browser-only code and after the element is mounted; a server render, a Node process, or a test environment without DOM shims cannot produce real measurements. jsdom does not perform layout and often returns zero or empty computed values, so unit tests should prefer createBox() or calculateBox() with explicit fixtures. The source accepts only computed spacing strings ending in px; rem, em, auto, and missing values become zero instead of throwing. One README sample says window.getComputedStyles(), but the actual code correctly uses window.getComputedStyle(). Finally, every getBox() call performs a geometry read and a style read. Batch measurements before DOM writes in animation or drag loops to avoid forced layout, and use calculateBox() when you already fetched the rect and styles.

Patterns

Read every box layer from an elementmeasure-element

import { getBox } from 'css-box-model';

const element = document.querySelector('[data-card]');
if (!(element instanceof HTMLElement)) throw new Error('card missing');

const box = getBox(element);
console.log(box.marginBox, box.borderBox, box.paddingBox, box.contentBox);

Call this only after the element is mounted and visible; it reads both layout and computed styles.

Get the content area's size and centerread-content-size

const { contentBox } = getBox(element);

console.log({
  width: contentBox.width,
  height: contentBox.height,
  centerX: contentBox.center.x,
  centerY: contentBox.center.y,
});

Coordinates are viewport-relative because the underlying border rectangle comes from getBoundingClientRect().

Read margin, border, and padding widthsinspect-spacing

const box = getBox(element);

console.log('margin top', box.margin.top);
console.log('border left', box.border.left);
console.log('padding right', box.padding.right);

Each spacing object has top, right, bottom, and left values in pixels; non-pixel computed strings become zero.

Convert viewport boxes to page coordinatesconvert-page-coordinates

import { getBox, withScroll } from 'css-box-model';

const viewportBox = getBox(element);
const pageBox = withScroll(viewportBox);
console.log(pageBox.borderBox.top);

withScroll() reads window.pageXOffset and pageYOffset by default, so do not call it during server rendering.

Apply an explicit scroll offsetapply-known-scroll

const pageBox = withScroll(viewportBox, {
  x: 0,
  y: 640,
});

Passing the position avoids a window read and makes the operation deterministic in tests.

Calculate from a rectangle and styles you already readreuse-dom-reads

import { calculateBox } from 'css-box-model';

const rect = element.getBoundingClientRect();
const styles = window.getComputedStyle(element);
const box = calculateBox(rect, styles);

Use this when other code already needs the same DOMRect and CSSStyleDeclaration; it avoids fetching them twice.

Create a box model without reading the DOMcreate-fixture

import { createBox } from 'css-box-model';

const box = createBox({
  borderBox: { top: 10, right: 210, bottom: 110, left: 10 },
  padding: { top: 8, right: 8, bottom: 8, left: 8 },
  border: { top: 1, right: 1, bottom: 1, left: 1 },
});

Omitted margin, border, or padding values default to zero on all four edges.

Turn four edges into a full rectanglenormalize-rectangle

import { getRect } from 'css-box-model';

const rect = getRect({ top: 20, right: 180, bottom: 100, left: 40 });
console.log(rect.width, rect.height, rect.x, rect.y, rect.center);

Width is right minus left and height is bottom minus top; reversed edges therefore produce negative sizes.

Expand a rectangle for hit testingexpand-hit-area

import { expand, getRect } from 'css-box-model';

const hitArea = getRect(expand(box.borderBox, {
  top: 8, right: 8, bottom: 8, left: 8,
}));

expand() returns only top, right, bottom, and left; pass the result through getRect() when you need width, height, or center.

Inset a rectangle on every edgeshrink-rectangle

import { shrink, getRect } from 'css-box-model';

const inner = getRect(shrink(box.borderBox, {
  top: 4, right: 4, bottom: 4, left: 4,
}));

Large inset values can cross the edges and produce a negative width or height; the helper does not clamp.

Move a complete box modeloffset-box-model

import { offset } from 'css-box-model';

const moved = offset(box, { x: 24, y: -12 });
console.log(moved.borderBox.left, moved.contentBox.top);

offset() rebuilds every layer from the shifted border box while preserving the original spacing values.

Annotate stored measurements in TypeScripttype-box-result

import { getBox, type BoxModel } from 'css-box-model';

let previous: BoxModel | null = null;
previous = getBox(element);

Version 1.2.1 includes its own declaration file, so no @types package is required.

Alternatives

PackageRegistryPick it when
@floating-ui/domnpmChoose it when you need popover placement, clipping, flipping, and middleware rather than only box arithmetic
get-css-datanpmChoose it when the task is reading a broader set of computed CSS properties from an element
compute-scroll-into-viewnpmChoose it when the end goal is calculating scroll actions that reveal an element