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

style-zx

v0.0.14

Published

**Zero-runtime CSS-in-JS with a `zx` prop.**

Readme

Style-ZX

Zero-runtime CSS-in-JS with a zx prop.

style-zx is a lightweight, zero-runtime CSS-in-JS library designed for Vite. It allows you to style your React components using a zx prop, which is compiled to static CSS classes at build time. This combines the developer experience of CSS-in-JS with the performance of static CSS.

Features

  • Zero Runtime: Styles are extracted to static CSS files during the build process. No runtime style injection or overhead.
  • Ultra Lightweight: The plugin output is tiny (~5KB), ensuring minimal impact on your build process.
  • zx Prop: Style any component directly with the zx prop (inspired by MUI's sx and other similar libraries).
  • createStyles: Define reusable static styles outside components that compile to class names.
  • TypeScript Support: Full type safety for CSS properties and theme variables.
  • Theming: Define a theme and access variables easily (e.g., "$theme.colors.primary").
  • Aliases: Shorthand properties for common styles (e.g., p, m, px, my, bg).
  • Nested Selectors: Support for pseudo-classes and nested selectors (e.g., &:hover, & > div).
  • Vite Integration: Seamless integration as a Vite plugin with HMR support.

Installation

  1. Install the package (assuming local or published package):

    npm install style-zx
    # or
    yarn add style-zx
  2. Add the Vite plugin in vite.config.ts:

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    import styleZx from 'style-zx/plugin'
    
    export default defineConfig({
      plugins: [styleZx(), react()],
    })

Usage

Basic Styling

Use the zx prop on any HTML element. Numeric values for dimensions are treated as pixels by default.

<div zx={{
  bg: 'white',
  p: 20, // padding: 20px
  borderRadius: 8,
  boxShadow: '0 4px 6px rgba(0,0,0,0.1)'
}}>
  <h1 zx={{ color: 'blue', fontSize: 24 }}>Hello World</h1>
</div>

Theming

Global Theme

Define your theme using createTheme. It injects CSS variables into :root and returns the theme object for direct JS access.

// src/theme.ts
import { createTheme } from 'style-zx';

export const theme = createTheme({
  colors: {
    primary: '#007bff',
    background: '#f0f2f5',
    text: '#333'
  },
  spacing: {
    small: 8,
    medium: 16
  }
});

Import the theme file early in your app (e.g., in main.tsx) to initialize CSS variables:

// main.tsx
import './theme';  // Initialize theme CSS variables
import App from './App';

Use theme variables in zx prop with $theme. prefix:

<button zx={{
  bg: '$theme.colors.primary',
  color: 'white',
  p: '$theme.spacing.small'
}}>
  Click Me
</button>

Scoped Themes (ThemeProvider)

Use ThemeProvider to override theme values for a section of your app. It inherits from the global theme and deep merges your overrides:

import { ThemeProvider } from 'style-zx';

// Only override what changes - everything else is inherited
<ThemeProvider theme={{ colors: { primary: '#a855f7', surface: '#1e1e2e' } }}>
  <Sidebar />  {/* Uses purple primary, inherits other colors */}
</ThemeProvider>

Nested ThemeProviders inherit from their parent:

<ThemeProvider theme={{ colors: { primary: 'blue' } }}>
  <ThemeProvider theme={{ colors: { secondary: 'green' } }}>
    {/* Gets blue primary + green secondary + all other inherited values */}
  </ThemeProvider>
</ThemeProvider>

useTheme Hook

Access the current theme in JavaScript with useTheme:

import { useTheme } from 'style-zx';

function MyComponent() {
  const theme = useTheme();
  return <p style={{ color: theme.colors.primary }}>Hello</p>;
}
  • Inside a ThemeProvider: returns the merged theme (parent + overrides)
  • Outside a ThemeProvider: returns the global theme

Nested Selectors

You can use standard CSS nesting syntax.

<div zx={{
  color: 'black',
  '&:hover': {
    color: 'blue'
  },
  '& > span': {
    fontWeight: 'bold'
  }
}}>
  Hover me <span>(Bold)</span>
</div>

createStyles

For reusable styles outside components, use createStyles. It compiles to static class names at build time with full support for aliases and theme variables.

import { createStyles } from 'style-zx';

const styles = createStyles({
  container: {
    bg: '$theme.colors.background',
    p: 20,
    display: 'flex',
    flexDirection: 'column',
  },
  title: {
    fontSize: '2em',
    color: '$theme.colors.primary',
    m: 0,
  },
  card: {
    bg: 'white',
    borderRadius: 8,
    boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
    p: 16,
  },
});

function App() {
  return (
    <div className={styles.container}>
      <h1 className={styles.title}>Hello</h1>
      <div className={styles.card}>Content here</div>
    </div>
  );
}

Conditional Classes: Use a library like clsx for conditional class logic:

import clsx from 'clsx';

<div className={clsx(styles.card, isActive && styles.active)} />

Comparison & Concept

The Concept

style-zx relies on static analysis. The build plugin scans your code for the zx prop, extracts the object literal, generates a unique class hash, creates CSS rules, and replaces the zx prop with a className.

vs. Pigment CSS

Both libraries aim for zero-runtime CSS-in-JS.

  • Pigment CSS: A more robust, complex solution often integrated with Next.js and MUI's ecosystem. It handles more complex dynamic scenarios but requires deeper integration. Also the project is not actively maintained at the moment.
  • Style-ZX: A lightweight, Vite-first approach. It focuses on simplicity and the specific zx prop API. It's easier to set up for simple Vite projects but may have fewer features than Pigment.

vs. Emotion / Styled-Components

  • Emotion/Styled-Components: Runtime CSS-in-JS. They parse styles in the browser, generate classes, and inject tags. This offers great flexibility (dynamic props) but incurs a runtime performance cost (script execution + style recalculation).
  • Style-ZX: No runtime cost. The browser just loads a CSS file.

vs. Tailwind CSS

  • Tailwind: Utility-first. You compose classes (p-4 bg-white).
  • Style-ZX: Object-based. You write CSS-like objects ({ p: 16, bg: 'white' }). This is often preferred by developers who like keeping styles colocated but find long class strings hard to read.

Caveats & Limitations

  1. Static Analysis Only: The values in zx must be statically analyzable at build time.
    • zx={{ color: 'red' }}
    • zx={{ color: '$theme.colors.primary' }} (if theme is static)
    • zx={{ color: props.color }} (Dynamic props are not supported directly in the build step. Use CSS variables for dynamic values).
  2. Vite Only: Currently designed specifically as a Vite plugin.
  3. No Dynamic Function Interpolations: You cannot pass a function to zx that depends on runtime state.

Gains

  • Performance: Zero JS runtime for styles means faster TTI (Time to Interactive) and less main-thread work.
  • Bundle Size: The plugin itself is extremely small (~5KB), keeping your dev dependencies lean.
  • Developer Experience: Write styles in TypeScript right next to your components. Get autocomplete and type checking.
  • Maintainability: Styles are scoped and colocated, reducing dead code and global namespace pollution.