Open-source project
mg901/styled-breakpoints avatar
mg901/styled-breakpoints

styled-breakpoints: named media query tiers for styled-components and Emotion

Powerful CSS-in-JS media queries with SSR support.

555 stars23 forksTypeScriptMIT

At a glance

What is it?
styled-breakpoints is a small TypeScript package that turns a set of named viewport widths into up, down, only and between media queries for styled-components or Emotion, with SSR support. It works for anyone who is tired of typing min-width strings by hand, and it is not a layout system.
Who is it for?
Adopt styled-breakpoints if your team already writes CSS in JavaScript through styled-components or Emotion and wants one shared set of named tiers instead of scattered min-width strings. Do not adopt it for a Tailwind or CSS Modules codebase, for runtime-only responsiveness, or if you need breakpoints that are not plain pixel widths.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Media query strings scattered through a component tree

Responsive CSS-in-JS has a recurring failure mode. A developer types a min-width value inline in a styled component, another developer types a slightly different one two files away, and the layout starts disagreeing with itself at the boundary where the two numbers meet. The problem is not that the media query is hard to write, it is that the width value is duplicated as a bare string in a dozen places, with nothing tying a query to a named intent.

styled-breakpoints addresses exactly that. It takes a set of named tiers and generates media query strings from them, so a query reads as a name rather than a number. The package description calls it CSS-in-JS media queries with SSR support, and the topics it lists cover styled-components, Emotion, React and responsive design, which places it squarely in the JavaScript styling layer rather than in a build-time CSS tool.

It is a narrow library on purpose. It does not decide your layout, it does not ship a grid, and it does not provide a design system. What it provides is a single source of truth for viewport widths plus four query shapes, and it delivers them into the theme object where your styling library can already reach.

Four query shapes: up, down, only and between

The core mechanism is a breakpoints object that lives on the theme. The documentation lists four APIs under Media Queries API, and each maps to a specific media query shape. The min-width variant is called up, the max-width variant is down, a single breakpoint range is called only, and a range of breakpoints is called between.

Because the object sits on the theme, a styled component reads it from the props that the styling library injects. The preview in the README shows the pattern for a styled component, where each query is interpolated into the template literal:

tsx
const Box = styled.div`
  background-color: pink;

  ${({ theme }) => theme.breakpoints.up('sm')} {
    background-color: hotpink;
  }

  ${({ theme }) => theme.breakpoints.up('md')} {
    background-color: red;
  }
`;

The same object is reachable from a hook, which is the part that matters for rendering decisions rather than styling. The documented example reads the theme with useTheme and passes a query into useMediaQuery:

tsx
import { useTheme } from 'styled-components'; // or '@emotion/react'

const Layout = () => {
  const theme = useTheme();
  const isMd = useMediaQuery(theme.breakpoints.up('md'));

  return <>{isMd && <Box />}</>;
};

The library supports styled-components and Emotion, and the useMediaQuery import comes from a separate entry point, styled-breakpoints/use-media-query, according to the exports map in package.json. That split keeps the hook out of the main entry when you do not need it.

Installing the package and creating the theme

Installation is a single npm or yarn command, and the README recommends the latest tag so you take the current published version:

bash
npm install styled-breakpoints@latest

# or

yarn add styled-breakpoints@latest

The theme is then created with a factory function, and the default configuration is one import and one call. The documented file layout puts the theme in its own directory with an index file and a declaration file for the styling library, alongside the app entry point:

tsx
import { createStyledBreakpointsTheme } from 'styled-breakpoints';

export const theme = createStyledBreakpointsTheme();

The declaration file exists so TypeScript knows about the theme shape. For styled-components the documented snippet augments the DefaultTheme interface, and Emotion has an equivalent augmentation for its Theme interface. Without that step, the theme property on styled component props is typed as unknown and the interpolation above will not typecheck.

So the first real use is not a media query, it is a type declaration. Add the breakpoints theme, augment the theme interface, then the query helpers become available on theme.breakpoints everywhere in the app.

Six default tiers you will probably have to change

The package ships six default breakpoints, described in the documentation as grid tiers. The values are the conventional set:

tsx
const breakpoints = {
  values: {
    xs: '0px',
    sm: '576px',
    md: '768px',
    lg: '992px',
    xl: '1200px',
    xxl: '1400px',
  },
};

The documentation notes that each breakpoint follows common responsive design conventions, with widths that are multiples of 12, and that they align with widely used viewport ranges but are not tied to specific devices. That wording is a warning in practice. The default values are a starting point that matches a widely used convention, not a contract with your design system. If your team's mockups use 640px or 1280px as the cut between tablet and desktop, every query in the codebase will be wrong at the edges until you override the values.

Overriding is a documented option, and the custom scale uses the same values key with your own names:

tsx
import { createStyledBreakpointsTheme } from 'styled-breakpoints';

export const theme = createStyledBreakpointsTheme({
  breakpoints: {
    values: {
      watch: '0px',
      mobile: '200px',
      tablet: '600px',
      laptop: '900px',
      desktop: '1400px',
    },
  },
});

The named tiers here are device words, which makes call sites readable. That is a design choice with a cost, since device names age badly as form factors shift, and the pixel-based defaults age more gracefully.

Folding the breakpoint theme into an existing theme

Most teams that reach for this already have a theme object with fonts, spacing and color. The library is written to merge rather than replace, and the documented pattern spreads the breakpoint theme into an existing theme object:

tsx
import { createStyledBreakpointsTheme } from 'styled-breakpoints';

const mainTheme = {
  fonts: ['sans-serif', 'Lato'],
  fontSizes: {
    small: '1em',
    medium: '2em',
    large: '3em',
  },
} as const;

export const theme = {
  ...mainTheme,
  ...createStyledBreakpointsTheme(),
};

export type AppThemeType = typeof theme;

The as const on the main theme and the exported AppThemeType are the part worth copying. Because the type is derived from the theme value, the declaration file in theme/ can extend the library interface with AppThemeType and every consumer of the theme gets the breakpoints keys typed.

Order matters here. The breakpoint theme is spread after the main theme, so if the main theme already contains a breakpoints key, the library value wins. Reversing the spread order would silently discard the breakpoint configuration, and nothing in the type system would complain.

What the package does not solve

Three boundaries are worth naming before you install anything.

First, the hook path is a client-side concern. useMediaQuery is for deciding what to render in React, which means the value can differ between the server and the browser if the server does not know the viewport width. The package advertises SSR support for the CSS side, where the media query is emitted as static CSS and the browser applies it. For the hook, the README does not document a server-side rendering strategy, so any layout that depends on it has to tolerate a default value on the first paint.

Second, the tiers are plain pixel widths. There is no documented support for em or rem units, for container queries, for orientation, or for a print variant. If your design system measures breakpoints in root font size, the generated queries will not line up with it.

Third, the library assumes a CSS-in-JS styling layer. The queries are consumed through the theme object and the interpolation syntax of styled-components or Emotion. In a Tailwind project or a plain CSS Modules project, there is no theme to hang them on, and the practical alternative is to write the media queries by hand.

The alternative: shared constants versus a styling layer

The realistic alternative to this package is not another media query library, it is a small shared constants module. Many codebases already export something like a breakpoints object with named widths and hand the values into template literals. That approach works, and it has two real advantages over styled-breakpoints: it has no dependency, and it works in any styling system.

The difference shows up in what the library adds on top of the constants. First, the query shapes. A constants module gives you the widths, and every developer still has to remember whether a given query is min-width, max-width, a single breakpoint range or a range between two, and whether a one-pixel overlap between down and up queries is intended. The up, down, only and between helpers encode that decision in one place.

Second, the theme integration. Because the breakpoints live on the theme, a styled component can reach them through the props the styling library already provides, and a single theme object carries the type. A constants module needs its own import and its own type story. The trade is dependency weight and the loss of framework neutrality. If your project is Tailwind-first, the constants module is the lighter and more honest choice.

Release cadence, licensing and the cost of the theme type

The project ships under the MIT licence, with a LICENCE file at the repository root and the package.json license field set to MIT, so using it inside a proprietary product carries no copyleft obligation beyond keeping the licence notice.

The release record is regular. Published versions include v15.0.4 on 2026-08-27, v15.0.3 on 2026-08-20 and v15.0.2 on 2026-07-02, and the last push was on 2026-10-16. The version numbering carries a major number that reaches fifteen, which is a signal that the public API has changed shape before and can change again. The repository runs on semantic-release and keeps a CHANGELOG.md, so the upgrade notes exist, but a major bump will require you to revisit call sites.

The package is published to npm under the name styled-breakpoints with the homepage pointing at the npm package page, and the published files are limited to the dist directory, with a separate production and development export for the main entry and a dedicated entry for the hook. The source is TypeScript, the build is driven by rolldown, and the test setup is vitest. The practical upgrade cost for a consumer is low: a dependency bump, then a typecheck of the theme augmentation in theme/styled.d.ts or theme/emotion.d.ts, which is where a breaking change in the theme shape would surface first.

Editorial conclusion

Adopt styled-breakpoints if your team already writes CSS in JavaScript through styled-components or Emotion and wants one shared set of named tiers instead of scattered min-width strings. Do not adopt it for a Tailwind or CSS Modules codebase, for runtime-only responsiveness, or if you need breakpoints that are not plain pixel widths. Verify first that the default values in the package match the widths your design system already uses, since xs through xxl are set to 0px, 576px, 768px, 992px, 1200px and 1400px and changing them changes every query in the codebase.

Frequently asked questions

How do I install styled-breakpoints?

Add the package with npm install styled-breakpoints@latest or yarn add styled-breakpoints@latest. You also need styled-components or Emotion, and the README shows a separate install command for each of them.

What are the default breakpoint values in styled-breakpoints?

Six tiers are included by default: xs at 0px, sm at 576px, md at 768px, lg at 992px, xl at 1200px and xxl at 1400px. They follow common responsive design conventions and can be replaced through the breakpoints values option in createStyledBreakpointsTheme.

How do I use the styled-breakpoints useMediaQuery hook?

Read the theme with useTheme from styled-components or '@emotion/react' and pass a query into useMediaQuery, for example useMediaQuery(theme.breakpoints.up('md')). The hook lives in its own export path, styled-breakpoints/use-media-query.

Can styled-breakpoints work with an existing theme?

Yes, the README shows spreading the result of createStyledBreakpointsTheme() into your own theme object and deriving an AppThemeType from the merged value, then augmenting the styled-components or Emotion theme interface with that type.

Is styled-breakpoints compatible with Tailwind CSS?

The package targets CSS-in-JS styling libraries and reaches breakpoints through the theme object, so it is built for styled-components and Emotion. The documentation does not describe a Tailwind integration.

Official sources

  1. License: MIT
  2. mg901/styled-breakpoints on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mg901-styled-breakpoints.svg)](https://hysenlabs.com/projects/mg901-styled-breakpoints)

Was this useful?