Getting started
Catalyst is a starter kit for building your own component systems with React and Tailwind CSS — 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.
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 framer-motion clsx
npm install @headlessui/react framer-motion clsx
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 * as Headless from '@headlessui/react'
import React, { forwardRef } from 'react'
import NextLink, { type LinkProps } from 'next/link'
export const Link = forwardRef(function Link(
props: { href: string } & React.ComponentPropsWithoutRef<'a'>,
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<Headless.DataInteractive>
<a {...props} ref={ref} />
<NextLink {...props} ref={ref} />
</Headless.DataInteractive>
)
})
import * as Headless from '@headlessui/react'
import React, { forwardRef } from 'react'
import NextLink, { type LinkProps } from 'next/link'
export const Link = forwardRef(function Link(
props: { href: string } & React.ComponentPropsWithoutRef<'a'>,
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<Headless.DataInteractive>
<a {...props} ref={ref} />
<NextLink {...props} ref={ref} />
</Headless.DataInteractive>
)
})
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 our own Heroicons icon set 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
Most components in Catalyst — like the Button
, DropdownItem
, and ListboxOption
components — are designed to work
best with 16×16 icons, so for these components 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>
)
}
The only exceptions are the NavbarItem
and SidebarItem
components which are designed for 20×20 icons. For
these components, import from @heroicons/react/20/solid
instead:
import { SidebarItem, SidebarLabel } from '@/components/sidebar'
import { HomeIcon } from '@heroicons/react/20/solid'
function Example() {
return (
<SidebarItem href="/home">
<HomeIcon />
<SidebarLabel>Home</SidebarLabel>
</SidebarItem>
)
}
import { SidebarItem, SidebarLabel } from '@/components/sidebar'
import { HomeIcon } from '@heroicons/react/20/solid'
function Example() {
return (
<SidebarItem href="/home">
<HomeIcon />
<SidebarLabel>Home</SidebarLabel>
</SidebarItem>
)
}
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 * as Headless from '@headlessui/react'
import NextLink, { type LinkProps } from 'next/link'
import React, { forwardRef } from 'react'
export const Link = forwardRef(function Link(
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<Headless.DataInteractive>
<NextLink {...props} ref={ref} />
</Headless.DataInteractive>
)
})
import * as Headless from '@headlessui/react'
import NextLink, { type LinkProps } from 'next/link'
import React, { forwardRef } from 'react'
export const Link = forwardRef(function Link(
props: LinkProps & React.ComponentPropsWithoutRef<'a'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<Headless.DataInteractive>
<NextLink {...props} ref={ref} />
</Headless.DataInteractive>
)
})
Integrating with Remix
Update your link.tsx
or link.jsx
file to use the Link
component from Remix:
import * as Headless from '@headlessui/react'
import { Link as RemixLink, type LinkProps } from '@remix-run/react'
import React, { forwardRef } from 'react'
export const Link = forwardRef(function Link(
props: { href: string | LinkProps['to'] } & Omit<LinkProps, 'to'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<Headless.DataInteractive>
<RemixLink {...props} to={props.href} ref={ref} />
</Headless.DataInteractive>
)
})
import * as Headless from '@headlessui/react'
import { Link as RemixLink, type LinkProps } from '@remix-run/react'
import React, { forwardRef } from 'react'
export const Link = forwardRef(function Link(
props: { href: string | LinkProps['to'] } & Omit<LinkProps, 'to'>,
ref: React.ForwardedRef<HTMLAnchorElement>
) {
return (
<Headless.DataInteractive>
<RemixLink {...props} to={props.href} ref={ref} />
</Headless.DataInteractive>
)
})
Integrating with Inertia.js
Update your link.tsx
or link.jsx
file to use the Link
component from Inertia.js:
import * as Headless from '@headlessui/react'
import { Link as InertiaLink, type InertiaLinkProps } from '@inertiajs/react'
import React, { forwardRef } from 'react'
export const Link = forwardRef(function Link(props: InertiaLinkProps, ref: React.ForwardedRef<HTMLAnchorElement>) {
return (
<Headless.DataInteractive>
<InertiaLink {...props} ref={ref} />
</Headless.DataInteractive>
)
})
import * as Headless from '@headlessui/react'
import { Link as InertiaLink, type InertiaLinkProps } from '@inertiajs/react'
import React, { forwardRef } from 'react'
export const Link = forwardRef(function Link(props: InertiaLinkProps, ref: React.ForwardedRef<HTMLAnchorElement>) {
return (
<Headless.DataInteractive>
<InertiaLink {...props} ref={ref} />
</Headless.DataInteractive>
)
})