Skip to main content
Theme UI provides a variety of UI components for building complete interfaces.

Button

The Button component is a primitive button with theme-aware variants.

Import

import { Button } from '@theme-ui/components'

Usage

<Button>Click me</Button>

Props

variant
string
default:"'primary'"
Button variant from theme.buttons
Button accepts all standard HTML button attributes and Box props.

Default Styles

{
  appearance: 'none',
  display: 'inline-block',
  textAlign: 'center',
  lineHeight: 'inherit',
  textDecoration: 'none',
  fontSize: 'inherit',
  px: 3,
  py: 2,
  color: 'white',
  bg: 'primary',
  border: 0,
  borderRadius: 4
}

Examples

<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button disabled>Disabled</Button>

The Link component is an anchor element with theme integration.

Import

import { Link } from '@theme-ui/components'

Usage

<Link href="/about">About</Link>

Props

variant
string
default:"'styles.a'"
Link variant from theme.links
Link accepts all standard HTML anchor attributes and Box props.

Examples

<Link href="https://theme-ui.com">External Link</Link>
<Link href="/docs" sx={{ color: 'primary' }}>Docs</Link>

The NavLink component is designed for navigation links with active states.

Import

import { NavLink } from '@theme-ui/components'

Usage

<NavLink href="/" className="active">Home</NavLink>

Props

variant
string
default:"'nav'"
Link variant from theme.links

Default Styles

{
  color: 'inherit',
  textDecoration: 'none',
  fontWeight: 'bold',
  display: 'inline-block',
  '&:hover, &:focus, &.active': {
    color: 'primary'
  }
}

Examples

<Flex as="nav" sx={{ gap: 3 }}>
  <NavLink href="/">Home</NavLink>
  <NavLink href="/about">About</NavLink>
  <NavLink href="/contact">Contact</NavLink>
</Flex>

Card

The Card component is a flexible container for content.

Import

import { Card } from '@theme-ui/components'

Usage

<Card>
  <Heading>Card Title</Heading>
  <Text>Card content</Text>
</Card>

Props

variant
string
default:"'primary'"
Card variant from theme.cards
Card accepts all Box props.

Examples

<Card p={4} bg="muted">
  <Heading mb={2}>Feature Card</Heading>
  <Paragraph>Description of the feature</Paragraph>
  <Button mt={3}>Learn More</Button>
</Card>

Badge

The Badge component displays small labels or tags.

Import

import { Badge } from '@theme-ui/components'

Usage

<Badge>New</Badge>

Props

variant
string
default:"'primary'"
Badge variant from theme.badges

Default Styles

{
  display: 'inline-block',
  verticalAlign: 'baseline',
  fontSize: 0,
  fontWeight: 'bold',
  whiteSpace: 'nowrap',
  px: 1,
  borderRadius: 2,
  color: 'white',
  bg: 'primary'
}

Examples

<Badge>New</Badge>
<Badge variant="secondary">Beta</Badge>
<Badge sx={{ bg: 'accent' }}>Hot</Badge>

Alert

The Alert component displays messages and notifications.

Import

import { Alert } from '@theme-ui/components'

Usage

<Alert>This is an alert message</Alert>

Props

variant
string
default:"'primary'"
Alert variant from theme.alerts

Default Styles

{
  display: 'flex',
  alignItems: 'center',
  px: 3,
  py: 2,
  fontWeight: 'bold',
  color: 'white',
  bg: 'primary',
  borderRadius: 4
}

Examples

<Alert variant="primary">Info message</Alert>
<Alert variant="success">Success message</Alert>
<Alert variant="error">Error message</Alert>

Avatar

The Avatar component displays user profile images.

Import

import { Avatar } from '@theme-ui/components'

Usage

<Avatar src="/avatar.jpg" />

Props

size
number | string
default:"48"
Width and height of the avatar
variant
string
default:"'avatar'"
Image variant from theme.images
Avatar accepts all standard HTML img attributes and Box props.

Default Styles

{
  borderRadius: 9999
}

Examples

<Avatar src="/user.jpg" size={64} />
<Avatar src="/profile.jpg" size={32} />

Spinner

The Spinner component displays a loading indicator.

Import

import { Spinner } from '@theme-ui/components'

Usage

<Spinner />

Props

size
number
default:"48"
Size of the spinner in pixels
strokeWidth
number
default:"4"
Width of the spinner stroke
title
string
default:"'Loading'"
Accessible title for the spinner
duration
number
default:"750"
Duration of the animation in milliseconds

Default Styles

{
  color: 'primary',
  overflow: 'visible'
}

Examples

<Spinner />
<Spinner size={64} />
<Spinner size={32} strokeWidth={2} />
<Spinner title="Loading content" duration={1000} />

Progress

The Progress component displays a horizontal progress bar.

Import

import { Progress } from '@theme-ui/components'

Usage

<Progress max={100} value={75} />

Props

max
number
Maximum value
value
number
Current value

Default Styles

{
  display: 'block',
  width: '100%',
  height: '4px',
  margin: 0,
  padding: 0,
  overflow: 'hidden',
  appearance: 'none',
  color: 'primary',
  bg: 'gray',
  borderRadius: 9999,
  border: 'none'
}

Examples

<Progress max={100} value={50} />
<Progress max={100} value={75} sx={{ color: 'success' }} />

Donut

The Donut component displays a circular progress chart.

Import

import { Donut } from '@theme-ui/components'

Usage

<Donut value={0.75} />

Props

value
number
required
Current value
min
number
default:"0"
Minimum value
max
number
default:"1"
Maximum value
size
string | number
default:"128"
Size of the donut chart
strokeWidth
number
default:"2"
Width of the donut stroke
title
string
Accessible title for the chart

Default Styles

{
  color: 'primary'
}

Examples

<Donut value={0.75} title="75% complete" />
<Donut value={60} min={0} max={100} size={96} />
<Donut value={0.5} sx={{ color: 'success' }} />

IconButton

The IconButton component is a transparent button for SVG icons.

Import

import { IconButton } from '@theme-ui/components'

Usage

<IconButton aria-label="Menu">
  <MenuIcon />
</IconButton>

Props

size
number | string
default:"32"
Width and height of the button
variant
string
default:"'icon'"
Button variant from theme.buttons

Default Styles

{
  appearance: 'none',
  display: 'inline-flex',
  alignItems: 'center',
  justifyContent: 'center',
  padding: 1,
  width: 32,
  height: 32,
  color: 'inherit',
  bg: 'transparent',
  border: 'none',
  borderRadius: 4
}

Examples

<IconButton aria-label="Settings">
  <SettingsIcon />
</IconButton>

<IconButton size={48} aria-label="Close">
  <CloseIcon />
</IconButton>

Close

The Close component is a button with a close (×) icon.

Import

import { Close } from '@theme-ui/components'

Usage

<Close />

Props

size
number
default:"32"
Size of the close button
variant
string
default:"'close'"
Button variant from theme.buttons

Examples

<Close onClick={handleClose} />
<Close size={24} />

Message

The Message component is a styled box for callouts and inline messages.

Import

import { Message } from '@theme-ui/components'

Usage

<Message>This is an informational message</Message>

Props

variant
string
Message variant from theme.messages

Default Styles

{
  padding: 3,
  paddingLeft: (t) => t.space[3] - t.space[1],
  borderLeftWidth: (t) => t.space[1],
  borderLeftStyle: 'solid',
  borderLeftColor: 'primary',
  borderRadius: 4,
  bg: 'highlight'
}

Examples

<Message>Info message with left border</Message>
<Message variant="warning">Warning message</Message>

Divider

The Divider component creates a horizontal rule.

Import

import { Divider } from '@theme-ui/components'

Usage

<Divider />

Props

Divider accepts all Box props and uses theme.styles.hr by default.

Default Styles

{
  color: 'gray',
  m: 0,
  my: 2,
  border: 0,
  borderBottom: '1px solid'
}

Examples

<Divider />
<Divider my={4} />
<Divider sx={{ borderColor: 'primary' }} />

Image

The Image component is a responsive image element.

Import

import { Image } from '@theme-ui/components'

Usage

<Image src="/photo.jpg" alt="Description" />

Props

variant
string
Image variant from theme.images
Image accepts all standard HTML img attributes and Box props.

Default Styles

{
  maxWidth: '100%',
  height: 'auto'
}

Examples

<Image src="/photo.jpg" alt="Photo" />
<Image src="/banner.jpg" sx={{ borderRadius: 4 }} />

Embed

The Embed component creates a responsive iframe container.

Import

import { Embed } from '@theme-ui/components'

Usage

<Embed src="https://www.youtube.com/embed/..." />

Props

src
string
URL of the embedded content
ratio
number
default:"16 / 9"
Aspect ratio of the embed
frameBorder
number
default:"0"
Frame border width
allowFullScreen
boolean
default:"true"
Allow fullscreen mode

Examples

<Embed src="https://www.youtube.com/embed/dQw4w9WgXcQ" />
<Embed src="https://player.vimeo.com/video/..." ratio={4/3} />

Complete UI Example

<Container py={4}>
  <Flex sx={{ justifyContent: 'space-between', alignItems: 'center', mb: 4 }}>
    <Heading>Dashboard</Heading>
    <Button>New Item</Button>
  </Flex>
  
  <Alert mb={3}>Welcome back! You have 3 new notifications.</Alert>
  
  <Grid columns={[1, 2, 3]} gap={4}>
    <Card p={4}>
      <Flex sx={{ alignItems: 'center', mb: 3 }}>
        <Avatar src="/user.jpg" size={48} />
        <Box ml={3}>
          <Heading as="h3">John Doe</Heading>
          <Badge>Admin</Badge>
        </Box>
      </Flex>
      <Divider />
      <Progress max={100} value={75} my={3} />
      <Text>Profile completion: 75%</Text>
    </Card>
    
    <Card p={4}>
      <Heading as="h3" mb={3}>Activity</Heading>
      <Donut value={0.65} size={96} />
    </Card>
    
    <Card p={4}>
      <Flex sx={{ justifyContent: 'space-between', mb: 3 }}>
        <Heading as="h3">Status</Heading>
        <IconButton aria-label="Refresh">
          <RefreshIcon />
        </IconButton>
      </Flex>
      <Spinner />
    </Card>
  </Grid>
</Container>

Build docs developers (and LLMs) love