Icons

All icons live in packages/web-ui/icons/ and are exported from two paths:

Import pathContents
@dbt-labs/web-ui/iconsAll icons including social re-exports
@dbt-labs/web-ui/icons/socialSocial platform icons only

Quick start

// Most icons
import { Arrow, Chevron, Close, CheckCircle } from '@dbt-labs/web-ui/icons'
 
// Social icons (available from both paths)
import { GitHub, LinkedIn, X } from '@dbt-labs/web-ui/icons/social'
import { GitHub, LinkedIn, X } from '@dbt-labs/web-ui/icons'
// Render at default size (24×24px)
<Close />
 
// Resize with Tailwind size utilities
<Close className='size-6' />
 
// Recolor with Tailwind text utilities
<Alert className='size-5 text-red-600' />
 
// Directional icon — pass a prop instead of importing a separate file
<Chevron direction='right' />
<Arrow direction='left' className='size-4' />

How icons work

currentColor

Every icon uses currentColor for its stroke or fill. That means the icon inherits whatever text color is active on the element — control it with Tailwind text utilities:

// Inherits the surrounding text color automatically
<p className='text-neutral-secondary'>
  <Clock className='inline-block size-4' /> 5 min read
</p>
 
// Override the color explicitly
<Alert className='text-error size-5' />

The one exception is Error, which uses hardcoded colors for its illustration — currentColor has no effect on it.

Sizing

Icons default to 24×24px (or 16×16px for Chevron weight='bold'). Use size-* to resize:

<Search className='size-4' />   // 16px
<Search className='size-5' />   // 20px
<Search className='size-6' />   // 24px — matches the SVG's natural size
<Search className='size-10' />  // 40px

Naming convention

The import path acts as the namespace, so no Icon suffix is used. Icons are named for what they communicate, not their shape:

// ✓ Correct
import { Close, Alert, Hyperlink } from '@dbt-labs/web-ui/icons'
 
// ✗ Old names — do not use
import { XMarkIcon, AlertIcon, LinkIcon } from '@dbt-labs/web-ui/icons'

Variant props

Several icons cover multiple related visuals through a single component with typed props. This avoids separate files for each direction or style:

ComponentPropOptionsDefault
Arrowdirection'left' | 'right''right'
Chevrondirection'up' | 'down' | 'left' | 'right''down'
Chevronweight'normal' | 'bold''normal'
CheckCirclevariant'mono' | 'brand''mono'
Uservariant'default' | 'plus''default'
LinkedInvariantnull | 'solid'null
// Chevron adapts to context — one import handles all four directions
<Chevron />                          // ∨ down (dropdown open indicator)
<Chevron direction='right' />        // > right (list item affordance)
<Chevron direction='up' />           // ∧ up (collapsed → expanded)
<Chevron weight='bold' direction='down' />  // bold stroke variant
 
// CheckCircle: brand uses orange + black; mono inherits currentColor
<CheckCircle variant='brand' />      // feature checklist (orange)
<CheckCircle />                      // success state (inherits color)

Link naming conflict

Hyperlink is named deliberately to avoid a collision with next/link's Link export. If you import both in the same file you can use them without an alias:

import Link from 'next/link'
import { Hyperlink } from '@dbt-labs/web-ui/icons'

Navigation

Icons used for orientation, movement, and menu interactions.

Arrow

Directional movement — links, sliders, carousels.

PropTypeDefault
direction'left' | 'right''right'
classNamestring—

Chevron

Dropdowns, accordions, collapsible nav. Default is down-pointing.

PropTypeDefault
direction'up' | 'down' | 'left' | 'right''down'
weight'normal' | 'bold''normal'
classNamestring—

Close

Dismiss dialogs, modals, drawers, and banners. Prefer this over a generic × glyph.

PropTypeDefault
classNamestring—

Login

Sign-in and authentication entry points.

PropTypeDefault
classNamestring—

Menu

Hamburger toggle for mobile navigation. Pair with Close for open/closed state.

PropTypeDefault
classNamestring—

Status

Icons that communicate state, feedback, or metadata.

Alert

Warning states and attention-required callouts.

PropTypeDefault
classNamestring—

CheckCircle

Success states and feature checklists. variant='brand' uses the orange/black brand palette; default uses currentColor.

PropTypeDefault
variant'mono' | 'brand''mono'
classNamestring—

Clock

Time estimates — read time, event duration, countdown.

PropTypeDefault
classNamestring—

Error

Error and empty-state illustrations. Note: renders a full-color SVG, not currentColor.

PropTypeDefault
classNamestring—

Info

Supplemental context and informational tooltips.

PropTypeDefault
classNamestring—

Action

Icons for interactive controls and content actions.

Hyperlink

External links and copy-URL affordances.

PropTypeDefault
classNamestring—

Minus

Remove, collapse, or decrement actions.

PropTypeDefault
classNamestring—

Plus

Add, expand, or increment actions.

PropTypeDefault
classNamestring—

Quote

Testimonials, pull quotes, and case study highlights.

PropTypeDefault
classNamestring—

Search

Search inputs and triggers.

PropTypeDefault
classNamestring—

User

Account and profile affordances. variant='plus' for sign-up / invite flows.

PropTypeDefault
variant'default' | 'plus''default'
classNamestring—

Media

Icons for audio, video, and content-type labeling.

Microphone

Podcast episodes, audio content labels.

PropTypeDefault
classNamestring—

Play

Video play buttons and media triggers.

PropTypeDefault
classNamestring—

Video

Video content labels and camera affordances.

PropTypeDefault
classNamestring—

Social

Social platform icons. Available from both @dbt-labs/web-ui/icons and @dbt-labs/web-ui/icons/social.

Bluesky

PropTypeDefault
classNamestring—

GitHub

PropTypeDefault
classNamestring—

Instagram

PropTypeDefault
classNamestring—

LinkedIn

variant='solid' fills the icon for profile/card contexts.

PropTypeDefault
variantnull | 'solid'null
classNamestring—

RSS

PropTypeDefault
classNamestring—

X

X (formerly Twitter) social icon. Not to be confused with Close (the dismiss ×).

PropTypeDefault
classNamestring—

YouTube

PropTypeDefault
classNamestring—

Adding a new icon

Before writing code

  • SVG path data from Figma, agreed name (PascalCase, communicative purpose — Bookmark not RibbonShape)
  • Decide if it has variants upfront — define the prop interface before touching a file
  • Write an intent note: one sentence on when and why to use it

No variants — 2 steps

1. Create packages/web-ui/icons/Bookmark.tsx

export const Bookmark = ({ className }: { className?: string }) => (
  <svg
    width='24'
    height='24'
    viewBox='0 0 24 24'
    fill='none'
    xmlns='http://www.w3.org/2000/svg'
    className={className}
  >
    <path
      d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'
      stroke='currentColor'
      strokeWidth='1.5'
      strokeLinecap='square'
      strokeLinejoin='round'
    />
  </svg>
)

2. Regenerate the barrel

npm run barrel -w packages/web-ui

This runs scripts/generate-icon-barrel.mjs, which globs every .tsx file in icons/ and icons/social/, sorts them alphabetically, and rewrites both index.ts files. You never edit icons/index.ts by hand — the script owns it.

The barrel also runs automatically before every npm run build and npm run dev via Turborepo, so if you forget, the next build will pick it up.

With variants — 1 file, typed prop

type StarVariant = 'outline' | 'filled'
 
export const Star = ({
  className,
  variant = 'outline',
}: {
  className?: string
  variant?: StarVariant
}) => (
  <svg viewBox='0 0 24 24' fill='none' className={className}>
    {variant === 'filled' ? (
      <path d='...' fill='currentColor' />
    ) : (
      <path d='...' stroke='currentColor' strokeWidth='1.5' />
    )}
  </svg>
)

Adding a future 'half-filled' variant: add to the StarVariant union, add a JSX branch. One file touched; TypeScript enforces the union everywhere it's used. Run npm run barrel -w packages/web-ui only if the filename changed — variants live in the same file so the barrel doesn't need updating.

Social icon

Drop the file in packages/web-ui/icons/social/ and run the barrel script — it handles icons/social/index.ts the same way. The icon is then available from both import paths:

import { NewSocialIcon } from '@dbt-labs/web-ui/icons/social'
import { NewSocialIcon } from '@dbt-labs/web-ui/icons'

Documentation checklist

  • Add a card under the correct category above
  • Visual preview, component name, props table, intent note
  • For variant icons, show each variant in the preview
  • Add an <IconDownload> component inside the card's <div className='p-4'> section, after the prop table — use icon={<ComponentName />} for single-variant icons, or variants={[...]} for multi-variant ones
  • Verify it renders in the Wildflower dev server

Deleting an icon

  1. grep -r 'ComponentName' apps/ packages/ — find all import sites first
  2. Migrate or remove all callsites
  3. Delete the .tsx file and the docs card above
  4. Run npm run barrel -w packages/web-ui — the deleted file is automatically removed from index.ts
  5. npm run build — TypeScript strict mode surfaces any missed references