https://github.com/argyleink/prop-for-that
what JS knows, now CSS knows
https://github.com/argyleink/prop-for-that
css custom-properties javascript
Last synced: 2 days ago
JSON representation
what JS knows, now CSS knows
- Host: GitHub
- URL: https://github.com/argyleink/prop-for-that
- Owner: argyleink
- License: mit
- Created: 2026-05-29T23:09:45.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-06-24T18:26:14.000Z (30 days ago)
- Last Synced: 2026-06-24T20:06:46.656Z (30 days ago)
- Topics: css, custom-properties, javascript
- Language: TypeScript
- Homepage: https://prop-for-that.netlify.app/
- Size: 876 KB
- Stars: 513
- Watchers: 4
- Forks: 6
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# prop-for-that
**Expose what JavaScript knows but CSS can't see — as live CSS custom properties.**
[](https://www.npmjs.com/package/prop-for-that)
[](https://bundlephobia.com/package/prop-for-that)


[**Docs**](https://prop-for-that.netlify.app/docsite/) · [**Demos**](https://prop-for-that.netlify.app/) · [**Changelog**](./CHANGELOG.md) · [**llms.txt**](https://prop-for-that.netlify.app/llms.txt)
---
Sliders, pointer position, element visibility, viewport size, battery, network, sensors — JavaScript can read all of it; CSS can't. **prop-for-that** writes that runtime state into `--live-*` and `--const-*` custom properties — batched and diffed down to one `setProperty` per frame — so your CSS can compose and react to it with plain `calc()` and `var()`.
Zero dependencies. TypeScript. ESM + CJS. SSR-safe.
```bash
npm i prop-for-that
```
## Quick start
```html
import 'prop-for-that/auto'
```
```css
/* the slider paints itself from its own value — no event listeners, no render loop */
input {
background: hsl(calc(var(--live-value-pct) * 120) 80% 50%);
}
```
Bind any element with `data-props-for="key …"` and read its `--live-*` properties in CSS. That's the whole idea.
## Why
- **CSS does the work.** No per-element event handlers or render loops — bind once, compose in stylesheets.
- **Fast by design.** One `requestAnimationFrame` flush per frame — idle when nothing changes, frozen while the tab is hidden — plus write-on-change diffing and a single shared `ResizeObserver` / `IntersectionObserver` for the whole page. Continuously-sampling element sources pause while their element is off screen; event-driven ones (form fields, ranges, selects) run ungated.
- **Ship only what you use.** Four lightweight core sources are built in; everything else is an opt-in, tree-shakeable plugin — and under `auto` each plugin loads on demand, the moment a `data-props-for` attribute asks for it.
- **Plays with the platform.** Opt into typed [`@property`](https://prop-for-that.netlify.app/docsite/concepts/typed-properties/) values for interpolation, or FOUC-safe constants written before first paint.
- **Tiny and dependency-free**, in every bundle format.
## What it can read
**Core** (built in): viewport, element size, visibility, and `` values.
**Plugins** (opt-in): pointer position, battery, network, online status, page focus & visibility, navigation type, page meta tags, low-entropy user-agent (OS / browser / engine / version / mobile), FPS, clock, scroll velocity, device orientation / motion, geolocation, CPU pressure, soft-keyboard geometry, media playback, form & field state, select & color-picker values, text-truncation (ellipsis) detection, and dominant + accent colors extracted from images and video — 20+ in all.
→ Every source, every property, and live demos are in the **[docs](https://prop-for-that.netlify.app/docsite/reference/plugins/)**.
## Entry points
| Import | What it does |
| --- | --- |
| `prop-for-that/auto` | Zero-config & declarative: binds every `data-props-for` element — globals included, via `` — loading plugin sources on demand, kept in sync with the DOM. Use as ``. |
| `prop-for-that` | Imperative API — `propsFor()`, `register()`, `configure()` — for explicit control and teardown. |
| `prop-for-that/head` | Synchronous, FOUC-safe constants (scrollbar width & overlay preference, DPR, core count, device memory, low-entropy user-agent) before first paint. |
| `prop-for-that/plugins` | The opt-in plugin catalog. |
> `auto` sees the **light DOM only** (not shadow roots — bind those with `propsFor(el, …)`), and lazy-loads plugin chunks, so from a CDN use one that serves the `dist` files verbatim (unpkg / jsDelivr), not a rewriting CDN.
Full API and concepts: **[prop-for-that.netlify.app/docsite](https://prop-for-that.netlify.app/docsite/)**.
## For LLMs / AI tools
A condensed, single-file reference — entry points, the full variable catalog, recipes, and gotchas — lives at **[llms.txt](./llms.txt)**, hosted at [prop-for-that.netlify.app/llms.txt](https://prop-for-that.netlify.app/llms.txt) and shipped in the npm package (`node_modules/prop-for-that/llms.txt`).
## License
MIT © [Adam Argyle](https://github.com/argyleink)