Theme UI scales, the sx pragma, and the keys your theme has to define
Build consistent, themeable React apps based on constraint-based design principles
At a glance
- What is it?
- Theme UI turns a theme object into React styles through the sx prop, the System UI Theme Specification and Emotion. Its edges are specific too: a pragma per file, key lookups with no documented fallback, and responsive arrays that walk one dimension.
- Who is it for?
- Adopt Theme UI when one layout has to be re skinned for several customers and you can commit to putting the pragma at the top of every styled file. Skip it when your team already runs Emotion with its own token file and has no plans for color modes.
- 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 114 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 6, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The sx prop needs a pragma at the top of the file
Styling an element with sx does not work by convention here. It works because the file carries a custom pragma at the top, and that pragma replaces the default React JSX functions for that module.
/** @jsxImportSource theme-ui */
export default (props) => (
<div
sx={{
fontWeight: 'bold',
fontSize: 4, // picks up value from `theme.fontSizes[4]`
color: 'primary', // picks up value from `theme.colors.primary`
}}
>
Hello
</div>
)The switch is per file, and that is the part that decides what adopting the library means for your tree: you choose which modules opt in, and the README says this removes the need for a Babel plugin or additional configuration. The cost lands on the other side of that choice. A file without the pragma has no sx handling at all, so one codebase ends up carrying two styling dialects, and nothing in the repository layout records which files opted in. A component shipped inside a prebuilt package compiled without the pragma gives you nothing to intercept either, so its styles have to be applied at the call site instead.
fontSize: 4 resolves to theme.fontSizes[4]
The example theme defines three font stacks and three colors, and stops there.
// example theme.js
export default {
fonts: {
body: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif',
heading: '"Avenir Next", sans-serif',
monospace: 'Menlo, monospace',
},
colors: {
text: '#000',
background: '#fff',
primary: '#33e',
},
}fontSize: 4 is an index into theme.fontSizes, and color: 'primary' is a key into theme.colors. That object is handed to ThemeUIProvider once, and any component below the provider reads from it without importing anything, which is the reason to put a theme in context at all. What the README does not document is a fallback for a key that is missing. A scale with three entries plus a component asking for fontSize: 4 has no documented answer, and the place that surfaces is the rendered page rather than a build error, so you find out by opening the app.
Responsive arrays walk one dimension in steps
Arrays as sx values are a step function, not a query. width: ['100%', '50%', '25%'] applies 100% at every viewport, 50% above the first breakpoint and 25% above the next, mobile first. This API came from Styled System, and the README frames it as a terser syntax for applying responsive styles across a singular dimension. Read that limitation literally. Width, padding and font size that have to move together at one breakpoint mean three parallel arrays kept in step by hand, and there is no documented way to name a breakpoint or group properties under one condition. If your responsive rules are not a single ladder up one axis, sx will not carry them and you are back to writing your own CSS.
The install command decides whether color modes come with it
Color modes and layout components decide which package you install.
npm install theme-ui @emotion/reactEmotion comes along because the library is built with it for scoped styles. The README then names a narrower entry point for a narrower case: if you do not need color modes or components, @theme-ui/core is enough. First use is the provider, wrapped once at the top of the app around a theme object of your own.
// basic usage
import { ThemeUIProvider } from 'theme-ui'
import theme from './theme'
export default (props) => (
<ThemeUIProvider theme={theme}>{props.children}</ThemeUIProvider>
)After those two steps, every value a component asks for resolves against one object. Built-in support for dark modes, primitive page layout components, a plugin for Gatsby sites, styling for MDX content and support for Typography.js themes are all listed too, which says the intended product is a design system rather than a single component.
Two doc sites, two branches, one version number
There are two documentation sites because the project ships from two branches. Stable docs sit at theme-ui.com, prerelease docs at dev.theme-ui.com, and the default branch of the repository is develop. The tags show that split in dates: v0.17.4 shipped on 2026-01-02, then v0.17.5-develop.0 and v0.17.5-develop.1 both landed on 2026-03-05, while the monorepo package.json still reads 0.17.4. The last push to this repository was on 2026-06-14. Check which branch a documented prop belongs to before you debug against dev.theme-ui.com, because the property you are chasing may describe a prerelease line that your lockfile never installed.
Emotion renders what the theme lookup returns
Emotion is the layer that turns each style object into CSS, and the comparison the README draws is with Emotion's own css prop. The mechanism is close to identical. A style object goes onto the element, and Theme UI adds theme lookups on top. That is the real difference in approach against writing plain values: with the css prop, sharing one brand color across twelve components means editing twelve call sites, while with a theme the color is a key read from one place. The price is the pragma in every styled file plus one more indirection between markup and CSS. A team already running Emotion with its own token file gets little from that trade, whereas a product that re-skins one layout for four customers gets the part it needs.
The repository root leaves upgrade and rendering questions open
The root of the repository is where the gaps become visible. MIGRATING.md and CHANGELOG.md both exist and the README links neither, so upgrade notes are a file you have to go find. A .size-limit.json sits there with no figure in the README, which leaves you unable to judge the bundle cost the authors consider acceptable before you build. The doc list ends at Theming, The sx Prop, Layout, Color Modes, Theme Spec, Themed, MDX Components, Gatsby Plugin and API, and the README gives no hint that server rendering or hydration is covered anywhere in that set. No rollback path between a stable release and a develop tag is documented either. Badges point at Cypress runs and a Percy project, so visual comparison runs in the pipeline even though the workflow behind them is not written down.
Editorial conclusion
Adopt Theme UI when one layout has to be re skinned for several customers and you can commit to putting the pragma at the top of every styled file. Skip it when your team already runs Emotion with its own token file and has no plans for color modes. Before either, open the file that will hold your provider and check the scale keys against the property names your components ask for, because the README documents no fallback for a key that is missing.
Frequently asked questions
What is Theme UI?
A library for creating themeable user interfaces based on constraint-based design principles, written in TypeScript and released under MIT. Styles reach elements through the sx prop, values resolve against a theme object that follows the System UI Theme Specification, and rendering runs through Emotion.
What is a UI theme in Theme UI?
It is the object you pass to ThemeUIProvider: font stacks, colors, and the scales that sx props look up. The object follows the System UI Theme Specification, which covers custom color palettes, typographic scales and fonts.
What does UI mean for Theme UI's layout components?
In this library the UI layer means components styled from the theme. Theme UI ships primitive page layout components and is meant to work with virtually any UI component library and with existing Styled System components rather than replacing them.
Official sources
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.
[](https://hysenlabs.com/projects/system-ui-theme-ui)