Skip to content

Adopting r$ in a site you already have

The tutorial builds a page from nothing. This is the other path: you have a codebase, media queries you did not write, and no appetite for a rewrite. Nothing here asks you to change a line of CSS until step 4 — and step 4 is optional.

Each step is useful on its own. Stop wherever the value stops.

Step 1 — Measure what you have (about a minute, nothing installed)

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

You get every width judged: what overflows, which targets are under the WCAG 24px floor, where contrast fails against the background actually painted, and — if the page scrolls sideways at any width — the document's own reach. Exit 0 pass, 1 violations.

If nothing is found, you have learned something real for the price of a minute. If plenty is found, do not fix it yet: pin it first.

No browser driver? npx @responsivejs/cli doctor tells you what is available and the exact install command for what is not.

Step 2 — Pin today's reality as a contract

bash
npx @responsivejs/cli init https://your-site.com -o site.contract.json

This works on a page that has never heard of r$: the rules that carry most of the value need neither a construct nor a selector you have to invent. You get a JSON file with the page-wide rules, plus baselines for the headings and body text it found. Read it — it is meant to be reviewed, not trusted blindly. Delete rules you disagree with, tighten the ones you care about.

bash
npx @responsivejs/cli record site.contract.json https://your-site.com   # pin today's curves

record measures the current type scale and writes it into the contract. From now on, a change to those curves is a diff in a reviewed file rather than a surprise.

Step 3 — Make it a gate

yaml
- run: npx @responsivejs/cli verify site.contract.json http://localhost:4173/ -d playwright

Run it against the built site, not the dev server. Two rules for keeping the gate trusted:

  • Start from green. If the audit found twenty violations, do not gate on all twenty on day one. Fix, or narrow the contract with when: { min, max } ranges, until it passes — a gate that is red on arrival gets ignored within a week.
  • Warnings are not failures. Only errors fail. ✓ 794/799 checks (5 warnings — no errors) is a pass, and the five are worth a look, not a build break.

At this point you have regression protection and have written no r$ code at all. For a lot of teams this is the whole adoption.

Step 4 — Replace the breakpoints that actually hurt

Now, and only now, is the runtime worth installing — and even then, one construct at a time. Start with the breakpoints that keep rotting, not with the ones that work:

bash
npm i @responsivejs/runtime

The burger that is wrong in German. A hand-picked @media (max-width: 843px) breaks when a link is added or the site is translated. Replace the number with the measurement:

typescript
r$.geometry('.site-nav', { wrapped: r$.whenWraps });
css
.site-nav[data-wrapped]         { visibility: hidden; height: 0; overflow: hidden; }
.site-nav[data-wrapped] ~ .burger { display: block; }

Your CSS keeps owning the appearance; JS only states the fact. And delete the media query — leaving both means two sources of truth.

The spacing ladder with three visible jumps. Three rules become one declaration that compiles to a clamp() and ships as CSS:

typescript
r$('.card', { padding: r$.fluid(12, 36) });

A component that must answer to its container, not the window — say how wide that container gets, which is required and not optional:

typescript
const panel = { container: true, from: 240, to: 820 };
r$('.card', { fontSize: r$.fluid(15, 26, panel) });

Re-run verify after each replacement. The contract you pinned in step 2 is now doing the job it was written for.

Step 5 — Let the constructs write the rules

Once the page runs the runtime, init reads more than the page:

bash
npx @responsivejs/cli init https://your-site.com -o site.contract.json

Every fluid value you declared becomes a monotonic + continuous rule and a baseline: what you declared becomes what CI verifies. Anything not yet expressible as a rule is printed, never dropped silently.

What not to do

  • Do not convert every media query. Most of them are fine. The ones worth replacing are the ones that encode a guess about content — how many links fit, whether the text was cut.
  • Do not gate on a contract you have not read. A generated file is a starting point.
  • Do not chase the aesthetic score. It is a heuristic, off by default, and no substitute for the measurements.

Troubleshooting when something does not behave · Why r$ when someone asks you to justify it.