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

bare-styled

v0.1.1

Published

styled-components without the wrapper fiber: a build-time transform (oxc or Babel) + a JSX runtime that resolves styled components to plain host elements, compiling CSS at build time where possible.

Readme

bare-styled

styled-components, without components.

bare-styled keeps the styled-components API — the same imports, templates, and cascade semantics — but removes the runtime that makes it slow. Styled components are resolved to plain host elements at JSX time (no wrapper component in the React tree), and their CSS is compiled at build time wherever possible, so most components never touch a CSS parser in the browser.

Measured against styled-components 6 on identical trees: ~24% faster mount, ~45% faster re-render on average, up to 58% on dynamic-heavy screens (median of repeated runs across nine profiles — see docs/perf-report.html). In a production app trace, styling CPU dropped 2.7×.

import styled from 'styled-components'; // unchanged

const Button = styled.button`
  padding: 8px 16px;
  background: ${p => (p.$primary ? '#e9679c' : '#1d2a4a')};
`;

<Button $primary>Save</Button>
// React renders: <button class="sc-x bs-a1b2">  — no wrapper fiber

Quick start (Vite)

// vite.config.ts
import { bareStyled } from 'bare-styled/vite';
import react from '@vitejs/plugin-react';

export default {
  plugins: [
    bareStyled(), // enforce: 'pre' — must come before react()
    react({ jsxImportSource: 'bare-styled' }),
  ],
};
// any global .d.ts — loads type augmentations (forwardProps, etc.)
import 'bare-styled/types';

That's the whole migration. Application code keeps importing styled-components; the plugin rewrites what it can prove safe and leaves everything else on real styled-components, so enabling it never changes behavior for the parts it doesn't compile.

How it works

No wrapper components. The build points the automatic JSX runtime at bare-styled. When a styled component is used, jsx() resolves it on the spot: styles become a hash class, props are filtered, and React receives the host element directly. A styled element costs one fiber, exactly like writing <button className=…> by hand. (Classic React.createElement is covered by a patch; elements created by unpatched third-party code still render correctly through a forwardRef fallback.)

Three compilation tiers, cheapest wins.

| tier | when | runtime cost | |---|---|---| | static | template fully resolvable at build (module constants, ${theme.x} chains, same-file ${Component} selectors and static css fragments) | zero — finished rule ships in the bundle | | skeleton | dynamic values only in declaration-value position (gap: ${p => p.gap};) | call the fns + string substitution — no CSS parser | | live | structure can change per render (block-position interpolations) | full resolve, aggressively cached |

In a large production codebase, ~81% of styled components land in the first two tiers and never run stylis in the browser.

Fast by default at build time too. The default transform engine is oxc-parser + magic-string (~0.8 ms per styled file, ~6× faster than the Babel engine, which remains available as the reference implementation and automatic per-file fallback).

Supported API

styled.tag, styled('tag'), styled(Component), styled(Compound.Member), styled(Comp<T>), extension chains styled(Styled), .attrs(...), .withConfig({ componentId, displayName, shouldForwardProp }), keyframes interpolation, ${Component} selectors, the as prop, transient $props, and statics passthrough (styled(Dropdown) still exposes Dropdown.Item).

forwardProps (bare-styled extension)

One call that shapes all element props — a faster, more direct replacement for shouldForwardProp and for hand-written prop-stripping wrapper components:

const Stack = styled.div.withConfig({
  forwardProps: ({ gap, align, ...rest }) => rest, // what the DOM receives
})`
  display: flex;
  gap: ${p => p.gap};
  align-items: ${p => p.align};
`;

Style interpolations still see the original props, so styling props can drive CSS while being stripped from the DOM. children always pass through; className from the shape merges after the generated classes; it applies once at the final target, so every template in an extension chain sees full props.

Safe fallback + diagnostics

Anything the transform can't prove safe — css / keyframes / createGlobalStyle helpers, unknown withConfig options, exotic chain shapes, function-scope definitions — stays untouched and runs on real styled-components. The Vite plugin warns whenever a file ends up with mixed rendering (some templates compiled, some left on styled-components), because cascade ties between the two sheets are not order-guaranteed.

BARE_STYLED_DEBUG=1 prints per-file stats during the build (templates compiled, build-precompiled, bailed). At runtime, __getFallbackRenders() reports how many styled elements paid a wrapper fiber through the forwardRef fallback — 0 in a correctly wired app, and each offender warns once in dev.

Limitations

ThemeProvider / context theming is not supported — a host element cannot read React context, so p => p.theme.x interpolations are dropped (the rest of the rule still applies). Use module-scope theme constants, or keep specific components on styled-components.

Parents that introspect their children's elements (child.props.width, child.type === Column) see the resolved host element, not the authored styled component — element resolution happens at creation time. Components whose elements a parent inspects should stay real components (a small wrapper).

Vendor prefixing is opt-in (styled-components v6 parity): call setVendorPrefixes(true) from the runtime and pass vendorPrefixes: true to the plugin so build-time and runtime rules match.

Other build setups

The Babel plugin works anywhere Babel does — pass the imported function, not a name string (a bare 'bare-styled' would be normalized to babel-plugin-bare-styled):

import bareStyled from 'bare-styled/transform';
// babel config: plugins: [[bareStyled, { /* options */ }]]

The raw fast engine is exposed as fastTransform(code, { filename }) from bare-styled/fast-transform for custom bundler integrations. Options for the plugin and both engines: engine ('oxc' default | 'babel'), displayName (default true), vendorPrefixes (default false), topLevelImportPaths, runtimeImportPath, namespace.

Development

pnpm install
pnpm build                          # babel src -d lib (both transform engines)
pnpm test                           # jest — runtime + transform + differential suites
node profiling/refresh-report.mjs   # rerun the perf matrix, rebuild docs/perf-report.html
node scripts/bundle-oxc.js          # regenerate vendor/oxc-parser.cjs after oxc bumps

MIT licensed.