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

@ryo9ra/su-css

v0.6.0

Published

素のHTMLだけで整ったUIを実現する、クラスレス・依存ゼロのアクセシブルなCSSフレームワーク / A zero-class, zero-dependency, accessible CSS framework for plain semantic HTML.

Readme

SuCSS

Just HTML, already styled.

CI npm License: MIT

A classless CSS framework. Write plain semantic HTML — no class names, no custom attributes — and get a liquid-glass design with dark mode and accessibility built in.

Demo: https://ryotasugawara.github.io/su-css/

Su (素) is Japanese for "plain" or "unadorned" — SuCSS styles plain HTML.

Features

  • No class names. Styling comes from the elements themselves: <header>, <main>, <article>, <button>, <dialog>, <table>, and friends.
  • Dark mode included. Follows prefers-color-scheme, and can be forced with data-theme="light" or data-theme="dark".
  • Accessible by default. WCAG AA/AAA contrast, visible :focus-visible rings, adequate touch targets, and prefers-reduced-motion / prefers-reduced-transparency support.
  • Liquid glass surfaces. Panels behave like a lens rather than a frosted sheet: the backdrop stays legible through them, colour blooms out of them, and every edge carries a specular rim. Controls are capsule-shaped and settle with a short overshoot.
  • Small and dependency-free. One CSS file, under 7 KB gzipped. No JavaScript, no build step.
  • Themeable. Every color, radius, and shadow is a CSS custom property.

Install

npm install @ryo9ra/su-css

| Import specifier | File | Size | | --- | --- | --- | | @ryo9ra/su-css | dist-lib/sucss.css | 70 KB (18.1 KB gzipped) | | @ryo9ra/su-css/sucss.min.css | dist-lib/sucss.min.css | 36 KB (6.6 KB gzipped) |

From a bundler (Vite, webpack, Next.js, …):

import '@ryo9ra/su-css/sucss.min.css';

Or straight from a CDN, with no install at all:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ryo9ra/su-css/dist-lib/sucss.min.css">

That URL always serves the newest release. While SuCSS is on 0.x, minor releases may still change how things look, so pin an exact version in production by appending it to the package name — @ryo9ra/[email protected]/dist-lib/sucss.min.css.

Usage

Link the stylesheet and write ordinary HTML. That is the whole API.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Website</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ryo9ra/su-css/dist-lib/sucss.min.css">
</head>
<body>
  <header>
    <nav>
      <strong>My Site</strong>
      <a href="#about">About</a>
    </nav>
  </header>

  <main>
    <article>
      <h1>Hello!</h1>
      <p>This page does not contain a single class name.</p>
      <button type="submit">Send</button>
      <button type="reset">Reset</button>
    </article>
  </main>
</body>
</html>

Interactive elements work natively too: <dialog> for modals, <details>/<summary> for accordions, <input type="checkbox" role="switch"> for toggles, and popovertarget with [popover] for a panel that opens and closes with no script at all — the panel shares its glass surface with <dialog> rather than a separate look of its own.

ARIA carries structure as well as state. A role="group" around a set of buttons spaces them as one cluster, and every button in it keeps the look its own markup gives it. Give those buttons aria-pressed (or the links aria-current) and the same group becomes a segmented control, because a set of buttons that carries a selection is a choice rather than a cluster. A role="toolbar" becomes a bar of commands, where an <hr> stands up as a separator and aria-orientation="vertical" stacks it.

A toolbar also asks Tab to enter it once and the arrow keys to move inside it. SuCSS draws the bar; that keyboard behaviour is yours to write. When you cannot, reach for role="group" instead — it carries no such expectation.

State works the same way. aria-invalid="true" marks a field as in error, aria-disabled and inert fade what cannot be operated, aria-busy puts a turning ring on what is still loading, aria-expanded turns a chevron toward what a button opens, aria-sort marks the column a table is ordered by, and a message that carries a sentence takes a block: role="alert" for something wrong, role="note" for something worth knowing. There is no success or warning colour, because severity has no ARIA role to hang one on.

Keeping aria-expanded in step with an open [popover] is the one thing the browser does not do for you — only <details> gets that for free. A few lines on the panel's own toggle event are enough; SuCSS's demo site does exactly that.

Theming

Override custom properties on :root. Shifting --hue recolors the whole page, including the background gradient.

:root {
  --hue: 210;               /* 0-360 */
  --sat: 80%;
  --radius: 12px;
  --glass-blur: 14px;       /* how far the material blurs what is behind it */
  --glass-saturate: 200%;   /* how much colour it pushes through */
  --glass-brightness: 1.04; /* lifts the backdrop in light mode; set below 1 to sink it */
}

The material itself is described by --glass-tint (the diagonal sheen), --glass-rim (the specular edge) and --glass-inset (the concave inner shadow on fields and tracks). --glass-brightness is what keeps text on glass readable as the surfaces get more transparent, so lower it rather than raising --glass-bg if a theme reads too washed out.

Dark mode follows the operating system by default. To control it yourself, set data-theme on <html>:

<html lang="en" data-theme="dark">

Browser support

Modern evergreen browsers: Chrome/Edge 111+, Safari 16.4+, Firefox 128+. Browsers without backdrop-filter fall back to solid surfaces.

Development

This repository also contains the demo site: hand-written HTML pages with no class attributes, styled entirely by the framework. index.html doubles as the element reference; customize.html is a live editor for the custom properties.

A page is a template plus a dictionary: src/pages/*.html holds the structure, src/locales/*.json holds every string on the site, one file per language. The build renders / and /ja/ from them, so each language ships as a real static page with the text in the markup and no JavaScript involved. The rendered pages are build output, not source — npm run dev and npm run build produce them.

npm install
npm run dev      # start the dev server
npm run build    # build the demo site
npm run lint     # TypeScript + Stylelint
npm run test     # unit, contrast, CSS structure and page tests
npm run build:pages  # render the pages on their own (dev and build do it first)
npm run build:review # one page showing every ARIA case, to look at a change

npm run build:review writes dist-review/index.html: every element, ARIA role and state the framework styles, each in its own document, against the current src/lib/sucss.css. It is one self-contained file with a light/dark and a phone/tablet/full switch, so a change can be looked at without running the site.

The framework itself is a single hand-written file: src/lib/sucss.css. npm run build:lib generates the distributable CSS, and npm run release:dry-run shows exactly what would be published.

Versioning is automated. Land Conventional Commits on main (feat:, fix:, feat!:) and release-please keeps a release PR open with the next version and changelog; merging it cuts the release. Releases then go through npm's staging queue, where a maintainer approves them with a 2FA challenge before they become installable.

The test suite parses src/lib/sucss.css directly: tests/css/contrast.test.ts checks every token pair against WCAG AA in both themes, and tests/css/structure.test.ts asserts the accessibility features promised above are actually present.

Conventions, the invariants the stylesheet has to hold to, and how to get a change released: CONTRIBUTING.md and docs/RELEASING.md.

To report a security problem, use private vulnerability reporting rather than an issue: SECURITY.md.

Brand

Icons, logos, the cover artwork and the palette live in assets/brand/, and how to use them is written down in docs/BRAND.md.

License

MIT