npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@useavalon/flora

v0.1.0

Published

Framework-agnostic, responsive modular grid system. CSS-first, token-driven, and trivially overridable — great DX with zero runtime dependencies.

Readme

Flora

CI

A framework-agnostic, responsive modular grid — CSS-first, token-driven, and trivially overridable. Zero runtime dependencies.

Flora gives you a mathematically-grounded modular grid (the 8-point system, sensible 4 / 8 / 12 responsive columns, baseline rhythm) that drops into any stack — plain HTML, React, Preact, Vue, Svelte, Solid, or a design system. Its whole job is to get out of your way: everything is a --flora-* custom property inside a low-priority @layer flora, so you customize by setting a variable and override any rule with an ordinary selector. No specificity fights, no !important, no quirks.

  • CSS-first. Import one stylesheet and add a class. No build step, no runtime.
  • Framework-agnostic. It's just CSS + custom properties. Use it anywhere, or nowhere.
  • Effortless override. All rules live in @layer flora; any unlayered rule you write wins automatically. Retune the grid by redefining a custom property.
  • Responsive by default. Mobile-first 4 / 8 / 12 columns with token-driven gutters and margins across the standard breakpoints.
  • Declarative spans. class="flora-col-6 flora-col-lg-4" or style="--flora-col-span: 6".
  • Optional <flora-grid> element. Zero-dependency web component for plain-HTML ergonomics.
  • Grid maths, exposed. Column widths, span widths, modular type scales, and divisibility helpers as pure functions.

Status: early (0.1.x). The API may change.


Install

npm install @useavalon/flora

Quick start (CSS)

import "@useavalon/flora/flora.css";
<div class="flora-grid">
  <div class="flora-col-4 flora-col-lg-8">main</div>
  <div class="flora-col-4 flora-col-lg-4">aside</div>
</div>

That's it — a responsive modular grid: 4 columns on mobile, 8 on tablet, 12 on desktop, with gutters and margins that scale per breakpoint.

Two ways to place items

<!-- utility classes, responsive per breakpoint -->
<div class="flora-col-6 flora-start-2 flora-col-lg-4">…</div>

<!-- or custom properties, inline / from your own CSS -->
<div style="--flora-col-span: 6; --flora-col-start: 2">…</div>

Overriding — the whole point

Flora ships inside @layer flora, the lowest-priority layer. Anything you write beats it, so you never fight the cascade:

/* 1. Retune a token — no rebuild, cascades normally. */
:root {
  --flora-gutter: 12px;
  --flora-columns: 16;
}

/* 2. Override a rule — an ordinary selector wins over the layer. No !important. */
.flora-grid {
  gap: 4rem;
}

Scope Flora to part of a page by generating it against your own selector (below), so there's no global .flora-grid at all if you don't want one.

Optional: <flora-grid> web component

import "@useavalon/flora/element"; // self-registers <flora-grid>
<flora-grid columns="12" gutter="24" margin="40" max-width="1200">
  <div class="flora-col-8">main</div>
  <aside style="--flora-col-span: 4">aside</aside>
</flora-grid>

The element only reflects its container attributes (columns, gutter, margin, row-gap, baseline, max-width) onto --flora-* properties. Children are placed with the same API as everywhere else — the flora-col-* classes or the --flora-col-span / --flora-col-start properties — so there's one mental model, not a separate attribute grammar. Its structural rules are injected into @layer flora too, so they stay overridable.

Generate a bespoke stylesheet

When you want a different column count, breakpoint set, or selector baked in:

import { generateGridCss } from "@useavalon/flora";

const css = generateGridCss({
  selector: "[data-grid]",
  columns: { xs: 2, md: 6, xl: 16 },
  gutter: { xs: 16, lg: 32 },
  maxWidth: 1440,
  layer: "flora", // or null to emit unlayered CSS
});

The generator is the single source of truth: the shipped flora.css is produced from the default config, so CSS and JS can't drift.

Layouts & recipes

All included in flora.css, all in @layer flora, all overridable.

Grid modes — retune gutters by adding a class:

<div class="flora-grid flora-condensed">…</div> <!-- 1px gutters -->
<div class="flora-grid flora-wide">…</div>      <!-- 32px gutters -->
<!-- also: flora-narrow (16px), flora-flush (0) -->

Native subgrid — nested items align to the outer grid's columns:

<div class="flora-grid">
  <section class="flora-subgrid flora-col-8">
    <h2 class="flora-col-6">…</h2>   <!-- aligns to the parent grid lines -->
    <aside class="flora-col-2">…</aside>
  </section>
</div>

Aspect-ratio boxes (media auto-covers):

<div class="flora-ratio-16x9"><img src="…" /></div>
<!-- 1x1, 2x1, 3x2, 4x3, 16x9, 2x3, 3x4 -->

Auto grid — responsive cards with no media queries:

<div class="flora-auto" style="--flora-auto-min: 16rem">
  <article>…</article> <!-- tracks fit automatically -->
</div>

Bento grid — dense, editorial tiles:

<div class="flora-bento">
  <div class="flora-tile-big">2×2</div>
  <div class="flora-tile-wide">2×1</div>
  <div class="flora-tile-tall">1×2</div>
  <div>1×1</div>
</div>

Masonry — variable-height items packed tightly with no fixed row lines:

<div class="flora-masonry" style="--flora-masonry-columns: 3; --flora-masonry-min: 16rem">
  <figure>…</figure> <!-- items keep their natural heights -->
  <figure>…</figure>
</div>

Native CSS masonry isn't broadly available yet (still experimental and behind flags, with the syntax being finalized), and Flora won't pull in a JS layout library — that would break the zero-dependency, CSS-first promise. So .flora-masonry is a progressive enhancement: today it uses CSS multi-column, which packs variable heights in every browser. The one caveat is that multi-column flows top-to-bottom within each column, so the visual order differs from source order — keep that in mind for reading order. The moment a browser ships native grid masonry, an @supports block automatically upgrades .flora-masonry to true grid masonry (which packs in source order and aligns to real column tracks) — no code change on your part, still no JS. Until then, .flora-bento remains a great source-order-preserving alternative.

16-column preset — a wider, powers-of-two grid (4 / 8 / 16) for dense, desktop-heavy layouts:

import { generateGridCss, POWERS_OF_TWO_COLUMNS } from "@useavalon/flora";

const css = generateGridCss({
  columns: POWERS_OF_TWO_COLUMNS, // 4 / 8 / 16
  maxSpan: 16,
});

Vertical rhythm

The counterpart to the column grid: keep vertical spacing on a baseline so text and blocks line up like ruled paper. Flora's baseline is --flora-baseline (defaults to the base unit, 8px).

<!-- consistent, baseline-multiple spacing between stacked children -->
<article class="flora-flow" style="--flora-flow-step: 3">
  <h1>Title</h1>
  <p>…</p>
  <figure>…</figure>
</article>

.flora-flow spaces adjacent children by --flora-baseline * --flora-flow-step (default 3 → 24px). Add .flora-baseline-grid to any element to paint a debug overlay every baseline unit and eyeball alignment.

Snap sizes to the grid in JS:

import { snapToBaseline, baselineLineHeight } from "@useavalon/flora";

snapToBaseline(20, 8);          // 24  (nearest 8px multiple)
baselineLineHeight(20, 8);      // 32  (line-height on the rhythm)

Or skip the manual math: a typeScale hands you font sizes and baseline-snapped line-heights together, so you can generate a whole scale that's already on the rhythm:

import { typeScale } from "@useavalon/flora";

const t = typeScale(16, "perfectFifth", { baseline: 8 });

for (const step of [-1, 0, 1, 2]) {
  console.log(`--fs-${step}: ${t.at(step)}px; --lh-${step}: ${t.lineHeightAt(step)}px;`);
}
// every line-height is a whole number of 8px baseline units

Container queries — respond to the slot, not the screen

Every responsive stylesheet ships in a @media (viewport) flavour and a @container flavour, so a grid or template composes based on its own container's width — ideal for a component reused in a wide main column and a narrow sidebar.

import "@useavalon/flora/flora.container.css"; // instead of flora.css
// and/or
import "@useavalon/flora/templates.container.css";
<aside class="flora-container">
  <!-- these columns react to <aside>'s width, regardless of the viewport -->
  <div class="flora-grid"> … </div>
</aside>

Add class="flora-container" (or container: flora / inline-size) to any ancestor; the container-flavoured grid/templates query it by name. Generate a custom one with generateGridCss({ query: "container" }) / generateTemplatesCss({ query: "container" }).

Print — layouts that survive paper & PDF export

Flora targets editorial layouts, the kind people actually print or export. Add the opt-in print stylesheet and your grids render sensibly on paper instead of overflowing:

import "@useavalon/flora/flora.css";
import "@useavalon/flora/flora.print.css"; // @media print rules

It only takes effect under @media print, and (like everything) lives in @layer flora. Out of the box it:

  • keeps cards, tiles, figures, and template slots from splitting across pages (break-inside: avoid);
  • collapses the responsive grid to full page width and drops the screen margins / max-width cap;
  • fits aspect-ratio media to the page instead of overflowing it;
  • turns the baseline debug overlay off and sets print-color-adjust: exact so backgrounds, borders, and tints survive the printer.

Two utilities and a few tokens let you steer it:

<!-- force a page break before/after any block (e.g. a template section) -->
<section class="flora-tmpl-cover flora-break-after">…</section>
<section class="flora-tmpl-editorial flora-break-before">…</section>

<!-- keep an arbitrary block whole; hide screen-only chrome on paper -->
<div class="flora-break-avoid">…</div>
<nav class="flora-screen-only">…</nav>
/* retune the print collapse without touching screen styles */
@media print {
  :root {
    --flora-print-margin: 12mm;   /* default 0    */
    --flora-print-max-width: none; /* default 100% */
    --flora-print-gutter: 8px;     /* default: the screen gutter */
  }
}

Generate a customized one (e.g. against your own grid selector) with generatePrintCss({ selector, layer }).

Templates — drop your components into ready-made layouts

Opt-in, editorial compositions built on grid-template-areas. Import the extra stylesheet, add a flora-tmpl-* class, and place your own components (any framework, or plain HTML) into named slots. They stack to one column on mobile and compose at md+.

import "@useavalon/flora/flora.css";
import "@useavalon/flora/templates.css";
<section class="flora-tmpl-cover">
  <p class="flora-area-eyebrow">Issue 01</p>
  <h1 class="flora-area-title">RETRO</h1>
  <div class="flora-area-meta">Spring 2025</div>
  <img class="flora-area-media" src="…" alt="" />
</section>

<!-- swap sides with flora-flip -->
<section class="flora-tmpl-split flora-flip">
  <MyGallery class="flora-area-media" />
  <div class="flora-area-content">…</div>
</section>

Included templates and their slots:

| Template | Slots | For | | --- | --- | --- | | flora-tmpl-cover | eyebrow title meta media | Brand / magazine covers | | flora-tmpl-split | media content (+flora-flip) | Heroes, about sections | | flora-tmpl-editorial | lede body figure pull | Article / newsletter spreads | | flora-tmpl-showcase | hero detail thumbs | Portfolio / project pages | | flora-tmpl-feature | head items | Strategy / feature sections | | flora-tmpl-toc | head list media | Table of contents / index | | flora-tmpl-team | head members | Team / people grids | | flora-tmpl-gallery | head gallery | Mixed-size image galleries |

Slots are just grid-areas, so you can also place a child with style="grid-area: title". And since it's all in @layer flora, retune any template with an ordinary rule — e.g. .flora-tmpl-cover { grid-template-columns: 2fr 1fr; }. Generate a customized set with generateTemplatesCss({ breakpoint, layer }).

Grid maths

Pure, framework-agnostic helpers:

import { columnWidth, spanWidth, typeScale, flexibilityScore } from "@useavalon/flora";

columnWidth({ container: 1200, columns: 12, gutter: 32, margin: 40 }); // 64
spanWidth({ container: 1200, columns: 12, gutter: 32, margin: 40, span: 6 }); // 544

const t = typeScale(16, "perfectFifth", { baseline: 8 }); // 3:2
t.at(1); // 24 — font size
t.at(-1); // 10.67
t.lineHeightAt(1); // 40 — line-height, snapped to the 8px baseline

flexibilityScore(12); // 4  — {2,3,4,6}; a prime like 13 → 0

Tokens

BASE_UNIT, SPACING_STEPS, BREAKPOINTS, SCALE_RATIOS, ASPECT_RATIOS, DEFAULT_COLUMNS/GUTTER/MARGIN, MIN_TOUCH_TARGET — exported as plain data to read in JS or feed to the generator.

Development

Flora is written in dependency-free TypeScript and ships its source. The examples double as the test suite (each asserts and prints ALL CHECKS PASSED):

bun install
bun run build          # tsc → dist, then generate dist/styles/flora.css
bun run demo           # generator
bun run demo:math      # grid maths
bun run demo:tokens    # default tokens
bun run demo:override  # override story

Open examples/index.html (after bun run build) for a live visual demo.

License

MIT © useAvalon