Styled System

A maintained, first-class-TypeScript rewrite of styled-system v5 - responsive, theme-aware style props for CSS-in-JS.

It is a drop-in replacement for the styled-system runtime: the root export surface matches upstream verbatim, and the package ships its own types (replacing @types/styled-system).

Features

  • Add style props that hook into your own theme
  • Quickly set responsive font-size, margin, padding, gap, width, and more with props
  • Influenced by constraint-based design-system principles
  • Typographic scale, and a spacing scale for margin, padding and gap
  • Works with any color palette
  • Works with most CSS-in-JS libraries, including Emotion and styled-components
  • First-class TypeScript types - theme-scale-aware props, replacing @types/styled-system

Install

# npm
npm install @soroush.tech/styled-system
# pnpm
pnpm add @soroush.tech/styled-system
# yarn
yarn add @soroush.tech/styled-system

@emotion/is-prop-valid (^1.4.0, peer) and prop-types (^15.8.1, optional peer) are each used by a single subpath - should-forward-prop and prop-types respectively. Install one only if you import that subpath. You bring your own CSS-in-JS library (Emotion, styled-components, ...); the core carries neither at runtime.

Usage

// Example uses Emotion, but styled-system works with most other CSS-in-JS libraries as well
import styled from '@emotion/styled'
import { space, layout, typography, color } from '@soroush.tech/styled-system'

// Add styled-system functions to your component
const Box = styled.div`
  ${space}
  ${layout}
  ${typography}
  ${color}
`

Each style function exposes its own set of component props that handle styles based on values defined in a theme.

// width: 50%
<Box width={1 / 2} />

// font-size: 20px (theme.fontSizes[4])
<Box fontSize={4} />

// margin: 16px (theme.space[2])
<Box m={2} />

// padding: 32px (theme.space[3])
<Box p={3} />

// color
<Box color="tomato" />

// color: #333 (theme.colors.gray[0])
<Box color="gray.0" />

// background-color
<Box bg="tomato" />

Responsive style props

Set responsive width, margin, padding, font-size, and other properties with a shorthand array syntax. See Responsive Styles.

// responsive width
<Box width={[1, 1 / 2, 1 / 4]} />

// responsive font-size
<Box fontSize={[2, 3, 4]} />

// responsive margin
<Box m={[1, 2, 3]} />

// responsive padding
<Box p={[1, 2, 3]} />

Subpath imports

Subpaths mirror the original @styled-system/* packages:

import { css } from '@soroush.tech/styled-system/css'
import { themeGet } from '@soroush.tech/styled-system/theme-get'
import { pick, omit } from '@soroush.tech/styled-system/props'
import propTypes, { createPropTypes } from '@soroush.tech/styled-system/prop-types'
import shouldForwardProp, {
  createShouldForwardProp,
  props,
} from '@soroush.tech/styled-system/should-forward-prop'

Drop-in via alias

Existing styled-system users can swap with a package-manager alias - no code changes:

"dependencies": {
  "styled-system": "npm:@soroush.tech/styled-system@^5"
}

The satellite @styled-system/* packages don't need separate aliases - import them as subpaths off the aliased styled-system name, and they resolve through this package's exports:

import themeGet from 'styled-system/theme-get'
import propTypes from 'styled-system/prop-types'
import { css } from 'styled-system/css'
import shouldForwardProp from 'styled-system/should-forward-prop'

Types resolve under both modern module resolution (node16/nodenext/bundler, via exports) and classic node (via typesVersions).

Documentation

Full docs live in docs/:

Runnable demos live in the examples repo.

Release notes

Per-version notes for every published release live in release-notes/.

License

MIT - a rewrite of styled-system (© 2017-2021 Brent Jackson), see LICENSE.

Releases

@soroush.tech/[email protected]

Maintenance release. No public API, behavior, or emitted-output changes - comments and docs only. No scale, prop, or generated style changed.

@soroush.tech/[email protected]

Maintenance release - build tooling only. No public API, behavior, or type changes. (#328)

Packaging

  • The workspace moved its formatter from Prettier to oxfmt, which wraps multi-line union types onto leading-pipe lines. That reformatted the ObjectOrArray declaration in src/types.ts; the type it describes is unchanged. No source, runtime, peer, or dev dependency changes.
  • typescript moves to ~7.0.2. It is a dev dependency here, used to typecheck and emit; the emitted output is unchanged.

@soroush.tech/[email protected]

Maintenance release - dependency refresh only. No public API or behavior changes. (#280)

Packaging

  • Dev-dependency bumps: eslint ^10.7.0^10.8.0, globals ^17.7.0^17.9.0, tsdown ^0.22.7^0.22.14. No runtime or peer dependency changes.

@soroush.tech/[email protected]

Scale flex and grid gaps on space, add aspectRatio to layout, and add whiteSpace and textOverflow to typography - six props the original styled-system never shipped. Additive and backward-compatible. (#313)

Added

  • gap, rowGap, columnGap - resolve against theme.space, the same scale (and default scale) as margins and paddings, and compose into space alongside margin and padding. Upstream only ever scaled the grid-prefixed gridGap/gridRowGap/gridColumnGap, so flex gaps had to be hand-wired through system(); that custom mapping can go. Typed via GapProps/RowGapProps/ColumnGapProps, composed into SpaceProps. The gap parser is also exported standalone, alongside margin and padding.
  • aspectRatio - maps straight to CSS aspect-ratio (no theme scale). Upstream's last release predates the property, so this too was hand-wired; that mapping can go as well. Typed via AspectRatioProps, composed into LayoutProps and re-exported from the /layout subpath.
  • whiteSpace and textOverflow - map straight to CSS white-space and text-overflow (no theme scale). Together with overflow from layout they make text truncation expressible in props alone, instead of dropping into raw CSS for the one declaration the parser was missing. Typed via WhiteSpaceProps/TextOverflowProps, composed into TypographyProps and re-exported from the /typography subpath, with both parsers also exported standalone alongside textAlign and textTransform.
  • All support responsive array and breakpoint-object values, and are filtered from the DOM automatically - none needs adding to a shouldForwardProp blocklist, since props derives from all.propNames.
  • Docs: Space props reference · Layout props reference · Typography props reference · prop/scale table · theme specification.

Upgrade

  • From 5.7.x: drop-in, no code changes. Components that hand-wired gap or aspectRatio through system() can delete that mapping and inherit the props from space/layout.

Packaging

  • No runtime or peer dependency changes.

@soroush.tech/[email protected]

Maintenance release - dependency refresh only. No public API or behavior changes.

Packaging

  • Dev-dependency bumps: tsdown ^0.22.4^0.22.7. No runtime or peer dependency changes.

@soroush.tech/[email protected]

Extend the typography style function with seven text-styling props the original styled-system never shipped - first-class, theme-aware props alongside textAlign and fontStyle. Additive and backward-compatible. (#258, #259)

Added

  • textTransform, textAlignLast, textDecoration, textDecorationLine, textDecorationStyle, textDecorationThickness - raw CSS pass-through props, each exported standalone and folded into TypographyProps; auto-covered by should-forward-prop.
  • textDecorationColor - resolves against the colors theme scale (like borderColor), in both the parser and the css() object-notation path.
  • Docs: Typography props reference · migration guide.

Upgrade

  • From 5.6.x: drop-in, no code changes.

Packaging

  • No runtime or peer dependency changes (dev-only tooling bumps).

@soroush.tech/[email protected]

Changes

  • Raise csstype runtime dependency floor ^3.1.3^3.2.3 (newer CSS property typings).
  • Repository moved to soroush-tech/core.

No public type or API changes.

@soroush.tech/[email protected]

Completes props-facing type parity with @types/styled-system - closes the drop-in gaps found migrating a real styled-system v5 monorepo (#215). Recommended upgrade from 5.5.0.

Fixed

  • themeGet matches @types/styled-system__theme-get verbatim - (path: string | Array<string | number>, fallback?: any) => (props: any) => any. No more unknown returns (TS2339 on destructuring) and no more rejecting component prop interfaces (TS2345). Array paths now also resolve as nested lookups (themeGet(['colors','primary'])), fixing a latent bug the upstream runtime never handled.
  • Public type surface loosened to any to match upstream - Props/Theme index signatures, Transform/StyleFn params, StyleObject, ConfigStyle.defaultScale, ThemeValue. Strict unknown/Props no longer breaks CSS-in-JS interpolation or arbitrary component props.
  • boxShadow / textShadow / fontWeight accept string | number - resolves against both object-keyed ({ sm, md }) and array-indexed ([...]) theme scales; restores array-index support that had been dropped.

Added

  • Upstream type-name aliases for drop-in imports: styleFn, Config, ConfigFunction, VariantArgs, LowLevelStyleFunctionArguments.

Changed

  • @emotion/is-prop-valid is now an optional peer dependency (peerDependenciesMeta) - no more missing peer warning for consumers who don't use the ./should-forward-prop subpath.
  • css exports CSSObject (was CssObject) to match @styled-system/css's actual name.

Upgrade

  • From 5.5.0: drop-in, no code changes. This makes the scoped-package migration described in #215 package.json-only.
  • 5.5.0 and earlier are deprecated (see notes).

@soroush.tech/[email protected]

Type-resolution fix for classic-node consumers, plus a parity correction to the package root. Recommended upgrade from 5.4.0 (now deprecated).

Fixed

  • Subpath types now resolve under classic moduleResolution: "node" (node10). Classic resolution doesn't read a package's exports map, so tsc couldn't find types for styled-system/theme-get, styled-system/prop-types, styled-system/core, etc. (TS2307), even though runtime worked. Added a typesVersions map (in publishConfig) pointing every subpath at its .d.cts - the mechanism classic node honors. No consumer changes required (no paths, no declare module, no moduleResolution change). Modern resolution (node16/nodenext/bundler) continues to resolve via exports.

Removed (parity)

  • The package root no longer exports themeGet or a default. The original styled-system main package exports neither - both only ever lived in the standalone @styled-system/theme-get. themeGet remains available (named + default) from the ./theme-get subpath: import themeGet from '@soroush.tech/styled-system/theme-get'.

Docs

  • Drop-in guidance now aliases the main styled-system name and imports satellites as subpaths off it - import themeGet from 'styled-system/theme-get' - which resolves through this package's exports (and typesVersions for node10).

Upgrade notes

  • From 5.4.0: drop-in. If you imported themeGet from the package root (5.3.0/5.4.0 only), switch to @soroush.tech/styled-system/theme-get.
  • 5.4.0 is deprecated (root default divergence + the node10 type gap fixed here).

@soroush.tech/[email protected]

Finishes drop-in parity with the styled-system@5 ecosystem - head-to-head is now 16/16 with the original packages. Builds on 5.3.0 (per-property prop types + Transform fix).

Added

  • ./prop-types subpath mirroring @styled-system/prop-types: propType, createPropTypes, and a default per-group map (space, color, layout, typography, flexbox, border, background, position, grid, shadow, buttonStyle, textStyle, colorStyle) built from each parser's propNames. Spread it onto a component: Box.propTypes = { ...propTypes.space, ...propTypes.color }.
  • themeGet as the package-root default export (in addition to the named export added in 5.3.0). A package-manager alias can only bind @styled-system/theme-get → the package root, so import themeGet from '@styled-system/theme-get' previously resolved to undefined; both import { themeGet } and import themeGet now work under the alias.

Notes

  • New optional peer dependency prop-types (^15.8.1) - required only if you import ./prop-types. It stays external in the build (~1.6 KB ESM), and the public types use a structural validator so consumers aren't forced to install @types/prop-types.
  • No runtime behavior change to existing exports; fully backward compatible.

@soroush.tech/[email protected]

Closes the remaining gaps for a true drop-in replacement of styled-system@5 + @types/styled-system (#213).

Added

  • Per-property prop types. Every atomic interface from @types/styled-system is now exported (WidthProps, HeightProps, OverflowProps, TopProps, ZIndexProps, AlignItemsProps, JustifyContentProps, FlexProps, FontSizeProps, FontWeightProps, LineHeightProps, TextAlignProps, TextColorProps, BackgroundColorProps, OpacityProps, BorderWidthProps, BorderStyleProps, BorderColorProps, BorderRadiusProps, BorderTop/Right/Bottom/LeftProps, BoxShadowProps, TextShadowProps, TextStyleProps, and the full Grid* and Background* families).
  • Each grouped interface (LayoutProps, FlexboxProps, BorderProps, ...) now composes its atomic interfaces via extends, matching upstream's structure.
  • All types are re-exported from their matching subpath (./layout, ./position, ./border, ...) as well as the main entry.
  • themeGet is now also available as a named export from the main entry: import { themeGet } from '@soroush.tech/styled-system'.

Changed

  • Transform is no longer unknown. It now matches @styled-system/core's (value: any, scale?: any) => any, so consumer transforms like (val) => MAP[val] ?? MAP.center compile without casts (no more TS2538).

Notes

  • boxShadow, textShadow, and fontWeight remain intentionally widened over upstream to also accept string theme keys.
  • No runtime behavior changes; fully backward compatible.
  • Still deferred: a @styled-system/prop-types equivalent (issue #213 §3).

@soroush.tech/styled-system v5.2.0

The first release of our ground-up rewrite of styled-system - a maintained, first-class-TypeScript implementation of responsive, theme-aware style props for CSS-in-JS.

It's a drop-in replacement for the styled-system v5 runtime: the root export surface matches upstream verbatim, so existing code keeps working, while everything underneath is new.

Highlights

  • Complete TypeScript rewrite - the entire style engine (system, compose, createParser, createStyleFunction, get) was rebuilt from scratch with first-class types. Every style function carries its own typed prop interface (SpaceProps, ColorProps, LayoutProps, ...).
  • Ships its own types - no more @types/styled-system. Types are theme-scale-aware and bundled in the package.
  • Dual ESM + CJS build with per-category subpath exports (/space, /color, /layout, /css, /theme-get, /props, /should-forward-prop, ...) mirroring the original @styled-system/* packages.
  • Tree-shakeable ("sideEffects": false), zero runtime CSS-in-JS dependency - bring your own Emotion or styled-components.
  • 100% test coverage, MIT licensed.

⚠️ Breaking change: propTypes dropped

Style functions no longer expose a propTypes property, and there is no prop-types companion package. The old @styled-system/prop-types is out of scope for this rewrite, and React 19 removed propTypes for function components entirely.

Migrate by using TypeScript for prop typing - each style function already provides a typed prop interface, so you get compile-time checking instead of runtime propTypes:

import { space, type SpaceProps } from '@soroush.tech/styled-system'

See the TypeScript guide.

Install

npm install @soroush.tech/styled-system

Existing styled-system users can swap with no code changes via a package-manager alias:

"dependencies": {
  "styled-system": "npm:@soroush.tech/styled-system@^5"
}

@emotion/is-prop-valid (^1.4.0) is a peer dependency, needed only if you import the should-forward-prop subpath.