Ver en Español
Theme UI in Next.js
Apr 12, 2023
Updated: Jun 25, 2026

Theme UI in Next.js

In this article you'll learn how to use Theme UI, a library that lets you create objects with a CSS theme (colors, variables, styles, etc.) and use them in your Next.js components. We'll also look at how to manage the scope of your styles and inject the CSS into your app.

An honest note before we start (2026). Theme UI is in maintenance mode today: its latest stable release (v0.17.4) is from January 2025, and the library predates React 19 and Next.js 16. It's still an excellent example for understanding the "theme as an object" concept and the sx prop, but if you're starting a new project in 2026 I'd recommend evaluating actively maintained alternatives: Tailwind CSS v4 (what this very site uses), CSS Modules, or zero runtime CSS libraries like Panda CSS or vanilla extract. Take this post as a conceptual guide; the ideas carry over nicely to those tools.

Installation

First, let's install the necessary packages and, of course, Theme UI:

npm i theme-ui @theme-ui/presets
# or
yarn add theme-ui @theme-ui/presets

Creating the theme

Create the theme in a JavaScript file at the root of your Next.js app and call it theme.js. The idea is simple:

  1. Write the theme as an object with the styles you need.
  2. Import a preset (a predefined configuration) from Theme UI and merge it with your extra styles.

Example theme.js:

import { roboto } from '@theme-ui/presets'

const theme = {
  ...roboto,
  containers: {
    // Container styles
  },
  styles: {
    ...roboto.styles,
  },
}

export default theme

Creating components

Now let's create components for our app, such as a navigation component.

A note on the JSX pragma. The original example opened every file with the classic /** @jsx jsx */ pragma plus an import { jsx } from 'theme-ui'. That's the classic JSX runtime, which is deprecated: React 17 onward (and React 19) use the automatic runtime. Theme UI's current guidance is to use /** @jsxImportSource theme-ui */ on the first line of the file, and you no longer need to import jsx manually. That's what we'll use in all of the examples.

Example nav.jsx:

/** @jsxImportSource theme-ui */
import Link from 'next/link'

const Nav = () => (
  <nav sx={{ display: 'flex', gap: 3, p: 3 }}>
    <Link href="/">Home</Link>
    <Link href="/notes">Notes</Link>
  </nav>
)

export default Nav

Notice the sx prop: it lets us write CSS directly in the component (inline CSS) and access the values defined in our theme object. For example, p: 3 takes the third value from the theme's spacing scale.

Using it in pages (Pages Router)

If your project uses the Pages Router, here's how to apply Theme UI in your pages. Remember to include the /** @jsxImportSource theme-ui */ pragma in every file that uses the sx prop.

// pages/index.jsx
/** @jsxImportSource theme-ui */
import Link from 'next/link'

export default function Home() {
  return (
    <main sx={{ p: 4 }}>
      <h1 sx={{ color: 'primary' }}>Home page</h1>
      <Link href="/notes">Go to notes</Link>
    </main>
  )
}
// pages/notes/index.jsx
/** @jsxImportSource theme-ui */
import Link from 'next/link'

export default function Notes() {
  return (
    <section sx={{ p: 4 }}>
      <h2 sx={{ color: 'secondary' }}>My notes</h2>
      <Link href="/">Back</Link>
    </section>
  )
}

Wrapping the app (Pages Router)

To make the theme available across the whole app, we wrap it with Theme UI's ThemeProvider component. In the Pages Router this goes in the pages/_app.jsx file:

// pages/_app.jsx
import { ThemeProvider } from 'theme-ui'
import theme from '../theme'
import Nav from '../src/components/nav'

export default function App({ Component, pageProps }) {
  return (
    <ThemeProvider theme={theme}>
      <div>
        <Nav />
        <Component {...pageProps} />
      </div>
    </ThemeProvider>
  )
}

Wrapping the app (App Router)

Next.js 16 uses the App Router (the app/ folder) by default. Because ThemeProvider holds state and uses the React Context API, it has to live in a client boundary, that is, inside a component marked with 'use client'. The recommended pattern is to create a provider component and render it from app/layout.jsx.

First, we create the client provider:

// app/providers.jsx
'use client'

import { ThemeProvider } from 'theme-ui'
import theme from '../theme'

export default function Providers({ children }) {
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>
}

Then we use it from the root layout, which remains a Server Component:

// app/layout.jsx
import Providers from './providers'
import Nav from '../src/components/nav'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Providers>
          <Nav />
          {children}
        </Providers>
      </body>
    </html>
  )
}

Note: the correct App Router pattern is to wrap ThemeProvider in a 'use client' component rendered from app/layout.jsx, just like any Context based provider in Next.js 16. See the Theme UI docs for server side style injection details, since the library was designed with the Pages Router in mind.

Conclusions

  • Theme UI lets you create CSS themes and apply them easily to your Next.js components (keep in mind the library is in maintenance mode).
  • You can import presets and add custom styles to your theme.
  • Use the sx prop to apply styles directly to your components and access the values in your theme object.
  • Remember to use the automatic JSX runtime (/** @jsxImportSource theme-ui */) and, in the App Router, to wrap ThemeProvider in a 'use client' component.

Theme UI is a useful, powerful tool with many features and a fair amount of depth. In this post we only covered the fundamentals for using it in your Next.js apps; the concept is the same for your React apps. That said, remember the note at the top: if you're starting something new in 2026, also evaluate the current alternatives.

I hope this post is useful to you and that you can apply it to a project you have in mind, or that it simply helped you understand how Theme UI works and how to apply it successfully to your Next.js projects.

If you have any questions, opinions, or want to add something, don't hesitate to leave a comment below. If you liked this article, share it using the social links at the bottom.

Suggested exercises

  1. Create a Next.js 16 project from scratch and implement Theme UI following the steps in this article, using the App Router and the /** @jsxImportSource theme-ui */ pragma.
  2. Explore different Theme UI presets and pick one that fits your needs.
  3. Create your own custom styles and apply them to different components in your app.
  4. As a comparison exercise, reimplement the same component with Tailwind CSS v4 or CSS Modules and compare the developer experience.

3-point summary

  1. Theme UI is a library that simplifies creating and applying CSS themes in your Next.js and React projects, though it's in maintenance mode today (consider Tailwind v4, CSS Modules, or Panda CSS for new projects).
  2. Theme UI presets provide predefined styles you can import and customize to your needs.
  3. Use the sx prop and the ThemeProvider component to apply your theme's styles; remember the automatic JSX runtime and the 'use client' boundary in the App Router.
Sebastian Gomez

Sebastian Gomez

Creador de contenido principalmente acerca de tecnología.

Leave a Reply

0 Comments

Advertisements

Related Posts

Categorias