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

sylphry

v1.0.0

Published

Lightweight, atomic, zero-config, framework-agnostic CSS-in-JS with tokens, theming & responsive breakpoints.

Readme

Sylphry

Atomic CSS-in-JS: framework-agnostic, tokenized theming & breakpoints—import and go.

npm License: MIT

🎯 Features

  • Atomic classes Generate single-purpose, composable CSS utilities.
  • Framework-agnostic Works in React, Vue, Svelte, or vanilla JS—no runtime deps.
  • Tokenized theming Define color, spacing, or design tokens once; switch themes at runtime.
  • Responsive breakpoints Built-in media variants—mobile-first with customizable breakpoints.
  • Zero config Just install and import; no extra setup, no build step required.
  • TypeScript support Fully typed API with token autocomplete and type-safe style keys.

📑 Table of Contents

🚀 Installation

npm install sylphry
# or
yarn add sylphry

🔧 Quickstart

import { createStyles } from "sylphry";

export default function Component() {
  return (
    <>
      <div className={styles.style1}>Hello</div>
      <div className={styles.style2}>World</div>
      <div className={styles(["style1", ["style2", false]])}>Merged</div>
      <div className={styles({ style2: true, style1: true })}>
        Another way to merge
      </div>
    </>
  );
}

const styles = createStyles({
  style1: {
    height: 100,
    width: 200,
    md: {
      height: 200,
      width: 300,
    },
    backgroundColor: "blue",
    ":hover": {
      backgroundColor: "green",
    },
  },
  style2: {
    height: 100,
    width: 200,
    "md:height": 200,
    "md:width": 300,
    backgroundColor: "orange",
  },
});

Composite Keys

Composite keys can be used as a shorthand for nested styles. Multiple breakpoints and pseudo styles can be combined, but only one CSSProperty can be used per composite key.

// breakpoint: sm, padding, :hover
"sm:padding:hover": <value>,
// "Create pseudo styling for :active:focus combo for both md and lg breakpoints
"md:lg:active:focus": { ... }

📖 API

createStyles(definitions, options?)

Returns a function that:

  • Accepts flags as an object { key: boolean } or an array of keys/tuples
  • Returns a unique class name string
  • Has properties for each key, e.g. styles.container

options param:

type Options = {
  // Set a prefix for the all generated classnames. Useful for finding classes in the browser
  prefix?: string;
};

setTheme(themeName)

Switches the active theme and rebuilds dynamic styles. Will use default theme if no matches are found.


🔄 Theming & Tokens

Global Breakpoint and Token Definitions

Setup

There are 2 steps:

  1. Create a config file at the root: sylphry.config.cjs
  2. Install the sylphry vite plugin

Config

At the root of the project, create a config file sylphry.config.cjs.

Config Interface:

type Config = {
  // Media breakpoint definitions
  breakpoints?: Record<string, string>;
  // Global token definitions
  tokens?: Record<string, string | number | Tokens>;
  // Default unit for numeric values - defaults to "px"
  defaultUnit?: string;
  // The current theme to reference in the tokens - defaults to "default"
  activeTheme?: string;
};

Example Config: sylphry.config.cjs

module.exports = {
  breakpoints: {
    phone: "100px",
    tablet: "500px",
  },
  tokens: {
    fontFamily: "Arial, Helvetica, sans-serif",
    default: {
      primary: "#3498db",
      secondary: "#e74c3c",
      accent: "#f1c40f",
      spacing: {
        xs: "2px",
        sm: "40px",
        md: "8px",
        lg: "16px",
        xl: "32px",
      },
      fontSizes: {
        sm: "12px",
        md: "16px",
        lg: "20px",
        xl: "24px",
      },
    },
    dark: {
      primary: "#1f3a93",
      secondary: "#c0392b",
      accent: "#f39c12",
    },
    light: {
      primary: "#5dade2",
      secondary: "#ec7063",
      accent: "#f7dc6f",
    },
  },
  activeTheme: "dark",
};

Vite Plugin

Install the Vite plugin in vite.config.ts

import { defineConfig } from "vite";
import sylphry from "sylphry/vite-plugin";

export default defineConfig({
  plugins: [sylphry()],
});

Token Usage

  • Use $tokenName$ in any string value to inject token colors, spacing, etc.
  • Supports default fallback if a token is missing in the active theme.
  • Tokens can also provide a path $path1:path2:tokenName$ to use specific tokens. This will still try to fallback to default if not found otherwise it will keep the original string.
const styles = createStyles({
  btn: {
    // Will attempt to find primary defined at the root, then at the active theme, then at the default theme
    background: "$primary$",
    ":hover": {
      // Will always use dark -> secondary even if the theme is something else
      background: "$dark:secondary$",
    },
  },
});

styles Options

The returned function from createStyles has an optional second param options.

type Options = {
  // Set a prefix for the generated classname. Useful for finding classes in the browser. This overrides the prefix set by createStyles
  prefix?: string;
  // Same structure as config. These token definitions will take priority over the tokens in the general config.
  tokens?: Tokens;
};

Example:

export default function Component() {
  const [color, setColor] = useState("green");
  const onClick = () => {
    setColor(prev => (prev === "green" ? "blue" : "green"));
  };

  return (
    <div
      className={styles(["style1"], {
        tokens: { color },
      })}
    >
      Hello
    </div>
  );
}

const styles = createStyles({
  style1: {
    backgroundColor: $color$,
  },
});

🛠️ Contributing

  1. Fork the Sylphry Repo
  2. Create your feature branch (git checkout -b feat/YourFeature)
  3. Commit your changes (git commit -m 'feat: add YourFeature')
  4. Push to the branch (git push origin feat/YourFeature)
  5. Open a Pull Request

Please follow the existing code style and run tests before opening a PR.


📄 License

This project is licensed under the MIT License. See LICENSE for details.