Skip to content

Getting started

ResponsiveJS (r$) is one model — value = f(width) — with two halves: author responsive behavior CSS can't express, verify the rendered result with measurements.

Start with the second half. It costs one command, changes nothing in your codebase, and tells you something true about a site you already have:

bash
npx @responsivejs/cli analyze https://your-site.com -w 320,375,768,1024,1280,1920

Every width judged: what overflows, which targets miss the WCAG 24px floor, where contrast fails against the background actually painted, whether the page scrolls sideways on a phone. Exit 0 pass, 1 violations — so it is a CI gate the moment you want one. Nothing installed, nothing imported, no decision made.

Liked what it found? Pin it as a contract — still without writing r$ code. Only then is the authoring half worth its install: it is for the cases CSS genuinely cannot express, not for replacing CSS you already have.

What it replaces

The hack you write todayThe r$ constructWhat you gain
A @media ladder for every sizer$.tokens({ '--space-m': r$.fluid(16, 24) })Smooth scaling, static clamp(), zero JS
The burger breakpoint that rotsr$.geometry('.nav', { wrapped: r$.whenWraps })Adapts by measurement — add a link, still correct
IntersectionObserver sticky-sentinelr$.whenStuck()One line, no sentinel DOM
Resize listeners + manual measuringr$.sync, r$.ratio, r$.fromElementCross-element relations, cleanup included
'mobile' strings that typo at runtimer$.breakpoints({...} as const)Names the compiler checks
Squinting at three screen sizesrjs analyze <url>Measured verdict at every width, exit-code gated
Screenshot diffing for regressionsrjs record / verify contractsThe layout's rules as reviewable JSON

Pick your entry:

I want to…InstallStart here
Audit a URL right now, zero setupnothing — npx @responsivejs/cli§ Audit
Author responsive behavior (fluid, geometry, tokens)npm i @responsivejs/runtime§ Authoring
Validate/score a page in CInpm i -D @responsivejs/design @playwright/test§ Validation
Score a live DOM without any drivernpm i @responsivejs/design§ Zero-driver
Pin a layout down as a verifiable contractnpm i -D @responsivejs/contract§ Contracts
Use it in React / Vue / Angularnpm i @responsivejs/react · /vue · /angular§ Adapters
Just the math (curves, geometry, WCAG, aesthetics)npm i @responsivejs/coreAPI: core
Drive r$ as an AI agentagents docs

No bundler? <script src="…/@responsivejs/runtime/dist/global.js"></script> gives you the same r$ on window (~15.5 kB gzip) — CMS pages, plain HTML, live demos.

All packages are ESM-only, zero runtime dependencies (Playwright and axe-core are optional peers of design), Node ≥ 20.19, MPL-2.0.

Audit (CLI)

bash
npx @responsivejs/cli analyze https://example.com -w 320,768,1280
# constraints + a11y · exit 0 pass / 1 violations · -f json|sarif · --score adds the heuristic

npx @responsivejs/cli audit https://example.com --vs https://competitor.com
# → one self-contained HTML report: screenshots with violation overlays, side-by-side

Driver-pluggable (Playwright, or agent-browser for any live URL with nothing installed). verify/record run the contract flow.

CLI reference · the design guide

Authoring

One import, the whole surface behind your editor's autocomplete:

typescript
import { r$ } from '@responsivejs/runtime';

const bp = r$.breakpoints({ mobile: 320, tablet: 768, desktop: 1024 } as const);

r$.tokens({ '--space-m': r$.fluid(16, 24), '--font-hero': r$.fluid(28, 64) });  // clamp() on :root
r$.geometry('.site-nav', { wrapped: r$.whenWraps });   // CSS: .site-nav[data-wrapped] { … }
r$('.cards', { gridTemplateColumns: bp.below('tablet', '1fr', 'repeat(3, 1fr)') });

r$ is CSS-first: everything expressible as clamp()/@media becomes one injected stylesheet; JS drives only what CSS cannot — non-linear curves, geometry state (wrap, overflow, sticky, truncation), cross-element dependencies (fromElement, sync, ratio). Add { container: true, from, to } to bind a value to the nearest container instead of the viewport — from/to are the container's own range, and are required.

the runtime guide (purposes, gradual examples, the mental model) · case studies · API: runtime · live example

Adapters

The constructs are framework-agnostic; the adapters own the lifecycle.

tsx
// React
const ref = useRef<HTMLDivElement>(null);
useResponsive(ref, { padding: r$.fluid(12, 24) });   // applied on mount, disposed on unmount
const isDesktop = useBreakpoint('desktop');
vue
<!-- Vue -->
<script setup>
const card = ref(null);
useResponsive(card, { padding: r$.fluid(12, 24) });
</script>
<template><div ref="card" v-responsive="{ gap: r$.fluid(8, 16) }" /></template>

Changing a declaration calls update() on the live handle instead of recreating it; React's StrictMode double-invocation is handled. Angular ships decorator-free helpers (injectResponsive, injectViewportWidth, …) that need no compilation step. → adapters reference

Validation

typescript
import { test, expect } from '@playwright/test';
import { r$ } from '@responsivejs/design';

test('layout holds at all widths', async ({ page }) => {
    const r = r$(page);
    await r.sweep({ url: 'http://localhost:3000', widths: [320, 768, 1280], selectors: ['h1', '.btn'] });
    r.assert.noOverflow().minSize('.btn', { height: 44 }).monotonic('h1', 'fontSize', 'up');
    expect(r.report().pass).toBe(true);
});

Or run the whole oracle in one call — constraints + aesthetic score + a11y (axe):

typescript
const report = await r$(page).sweep({ ... }).then((r) => r.analyze());
// UnifiedReport: { pass, violations, fixes, scores, summary, … }

the design guide (measure → model → judge) · API: design · guide: CI

Zero-driver

The browser subpath runs anywhere a DOM exists — no Playwright:

typescript
import { scoreDOM, analyzeStore, collectStore } from '@responsivejs/design/browser';

const { average, suggestions } = scoreDOM(['main', '.card']);   // 17-metric aesthetic score
const report = analyzeStore(collectStore(['main', '.card']));   // full constraint report

Inject it into any page via a driver's eval (CDP, agent-browser) — see the agents guide.

Contracts

typescript
import { contract } from '@responsivejs/contract';
import { verifyContract } from '@responsivejs/design';

const home = contract('home')
    .select('sidebar', '.app-sidebar')
    .assert('noOverflow', undefined, { id: 'no-bleed' })
    .below(768).assert('hidden', { selector: '$sidebar' }, { id: 'sidebar-mobile' })
    .from(768).assert('visible', { selector: '$sidebar' }, { id: 'sidebar-desktop' })
    .build();

const report = await verifyContract(home, page);   // sweep derived from the contract

Contracts serialize to JSON (published schema), travel with the repo, and double as the machine-readable spec agents enforce.

API: contract · guide: CI

Development setup (this repo)

bash
git clone https://github.com/AleSaiani/ResponsiveJS.git && cd ResponsiveJS
pnpm install
pnpm test        # unit tests, plain Node
pnpm typecheck   # no build needed (source-resolved)
pnpm build       # tsc, topological
pnpm test:e2e    # needs: pnpm --filter @responsivejs/design exec playwright install chromium