Getting started
Catalyst is a starter kit for building your own component systems with React — designed and developed by the Tailwind CSS team. It's a collection of beautiful, production-ready UI components you drop into your projects alongside your own code that are yours to customize, adapt, and make your own.
Catalyst is currently in development preview with unstable dependencies.
While not planned, we may need to introduce breaking changes in these dependencies on the road to Catalyst v1.0.
Before you start
Before you do anything else, make sure you've got a Tailwind CSS project set up that you'd like to use with Catalyst. Catalyst is built with React but isn't coupled to any specific React framework and can be used with Next.js, Remix, Inertia, or in any other React project.
For help creating a project and configuring Tailwind CSS, check out the framework guides in the Tailwind CSS documentation.
Catalyst is built around Tailwind's default theme configuration and relies on the default spacing scale, color palette, shadow scale, and more. You're of course free to customize anything you like, but you won't get the expected results out-of-the-box if you've made significant changes to the default theme and will need to edit the components to adapt them for your customizations.
Adding Catalyst to your project
To get started with Catalyst, first download the latest version from within your Tailwind UI account.
Then, unzip catalyst-ui-kit.zip
and copy the component files from either the javascript
or typescript
folders into wherever you keep components in your own project:
Installing dependencies
Next install the dependencies used by the components in Catalyst:
npm install @headlessui/react@next clsx
npm install @headlessui/react@next clsx
Catalyst is currently in development preview and depends on a development build of Headless UI, so be sure to install @headlessui/react
using the next
tag.
Catalyst is also designed for the latest version of Tailwind CSS, which is currently Tailwind CSS v3.4. To make sure that you are on the latest version of Tailwind, update it via npm:
npm install tailwindcss@latest
npm install tailwindcss@latest
Client-side router integration
By default, the Link
component in Catalyst renders a plain HTML <a>
element. You should update this component in your link.tsx
or link.jsx
file to use the link component provided by whichever framework or routing library you're using in your project.
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import React from 'react'
import NextLink, { type LinkProps } from 'next/link'
export const Link = React.forwardRef(function Link(
props: { href: string } & React.ComponentPropsWithoutRef<'a'>,
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<a {...props} ref={ref} />
<NextLink {...props} ref={ref} />
</HeadlessDataInteractive>
)
})
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import React from 'react'
import NextLink, { type LinkProps } from 'next/link'
export const Link = React.forwardRef(function Link(
props: { href: string } & React.ComponentPropsWithoutRef<'a'>,
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<a {...props} ref={ref} />
<NextLink {...props} ref={ref} />
</HeadlessDataInteractive>
)
})
We've provided ready-to-go examples for Next.js, Remix, and Inertia.js at the bottom of this page.
Optional: Setup Inter font family
We've designed Catalyst using Inter to ensure that the components look the same in all browsers and operating systems.
If you'd like to use Inter in your own projects, start by checking the documentation for the framework you're using — it's not uncommon for frameworks to have dedicated APIs for configuring custom fonts to simplify the developer experience.
If the framework you're using doesn't have a recommended way of setting up custom fonts, the easiest way to add Inter is by pointing a <link>
tag to the CDN:
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
Then add "Inter"
to your "sans"
font family in your tailwind.config.js
file:
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans],
},
},
},
// ...
}
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans],
},
},
},
// ...
}
Optional: Install Heroicons
We're using Heroicons (an icon set we designed ourselves) in Catalyst any time we need icons, and Heroicons has been designed to integrate seamlessly with Catalyst projects.
If you'd like to use Heroicons in your own projects, you can install it via npm:
npm install @heroicons/react
npm install @heroicons/react
The components in Catalyst are designed to work best with 16×16 icons, so import the icons you need from @heroicons/react/16/solid
:
import { Button } from '@/components/button'
import { PlusIcon } from '@heroicons/react/16/solid'
function Example() {
return (
<Button>
<PlusIcon />
Add item
</Button>
)
}
import { Button } from '@/components/button'
import { PlusIcon } from '@heroicons/react/16/solid'
function Example() {
return (
<Button>
<PlusIcon />
Add item
</Button>
)
}
Framework integration examples
By default, the Link
component in Catalyst renders a plain HTML <a>
element. These examples show you how to update your Link
component to use the Link
component provided by your framework or routing library.
Integrating with Next.js
Update your link.tsx
or link.jsx
file to use the Link
component from Next.js:
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import NextLink, { type LinkProps } from 'next/link'
import React from 'react'
export const Link = React.forwardRef(function Link(
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<NextLink {...props} ref={ref} />
</HeadlessDataInteractive>
)
})
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import NextLink, { type LinkProps } from 'next/link'
import React from 'react'
export const Link = React.forwardRef(function Link(
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<NextLink {...props} ref={ref} />
</HeadlessDataInteractive>
)
})
Integrating with Remix
Update your link.tsx
or link.jsx
file to use the Link
component from Remix:
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import { Link as RemixLink, type LinkProps } from '@remix-run/react'
import React from 'react'
export const Link = React.forwardRef(function Link(
props: { href: string | LinkProps['to'] } & Omit<LinkProps, 'to'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<RemixLink {...props} to={props.href} ref={ref} />
</HeadlessDataInteractive>
)
})
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import { Link as RemixLink, type LinkProps } from '@remix-run/react'
import React from 'react'
export const Link = React.forwardRef(function Link(
props: { href: string | LinkProps['to'] } & Omit<LinkProps, 'to'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<RemixLink {...props} to={props.href} ref={ref} />
</HeadlessDataInteractive>
)
})
Integrating with Inertia.js
Update your link.tsx
or link.jsx
file to use the Link
component from Inertia.js:
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import { Link as InertiaLink, type InertiaLinkProps } from '@inertiajs/react'
import React from 'react'
export const Link = React.forwardRef(function Link(
props: InertiaLinkProps,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<InertiaLink {...props} ref={ref} />
</HeadlessDataInteractive>
)
})
import { DataInteractive as HeadlessDataInteractive } from '@headlessui/react'
import { Link as InertiaLink, type InertiaLinkProps } from '@inertiajs/react'
import React from 'react'
export const Link = React.forwardRef(function Link(
props: InertiaLinkProps,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<HeadlessDataInteractive>
<InertiaLink {...props} ref={ref} />
</HeadlessDataInteractive>
)
})