Claude
Skills
Sign in
Back

joy-ui

Included with Lifetime
$97 forever

Joy UI — MUI's alternative design system with CSS variables, modern aesthetics, and simpler API

Design

What this skill does


# Joy UI

## What is Joy UI?

Joy UI (`@mui/joy`) is MUI's alternative component library that offers a modern, clean design language distinct from Google's Material Design. It is built from the ground up with CSS variables as a first-class feature, a flexible variant system, and a simpler API surface compared to Material UI.

```bash
npm install @mui/joy @emotion/react @emotion/styled
# or
pnpm add @mui/joy @emotion/react @emotion/styled
```

Joy UI shares MUI's engineering quality (accessibility, TypeScript, composability) but makes different design decisions:

- **CSS variables by default** -- not experimental, not opt-in
- **Variant system** -- every component supports `solid`, `soft`, `outlined`, `plain`
- **Color system** -- semantic colors (`primary`, `neutral`, `danger`, `success`, `warning`) instead of `primary`/`secondary`
- **Decoration levels** -- replaces Material UI's `elevation` with a more flexible concept
- **Modern aesthetic** -- rounded, spacious, contemporary look out of the box

## When to Use Joy UI

| Scenario | Recommendation |
|----------|---------------|
| App should NOT look like Material Design | Joy UI |
| Want CSS variables without experimental flags | Joy UI |
| Need Google Material Design compliance | Material UI |
| Building a modern SaaS dashboard | Joy UI |
| Existing Material UI codebase | Material UI (or gradual migration) |
| Need the largest component catalog | Material UI (more components today) |
| Want built-in dark mode with zero config | Joy UI |

## Key Differences from Material UI

### Variant System

Material UI uses `variant` on some components (`contained`, `outlined`, `text` for Button). Joy UI applies a consistent variant system across ALL components:

| Variant | Description | Use Case |
|---------|-------------|----------|
| `solid` | Filled background, high emphasis | Primary actions, selected states |
| `soft` | Subtle background tint | Secondary actions, tags, badges |
| `outlined` | Border only | Tertiary actions, form fields |
| `plain` | No background or border | Low-emphasis, text-like actions |

```tsx
import Button from '@mui/joy/Button';
import Chip from '@mui/joy/Chip';
import Alert from '@mui/joy/Alert';

// Every component supports all four variants
<Button variant="solid">Submit</Button>
<Button variant="soft">Draft</Button>
<Button variant="outlined">Cancel</Button>
<Button variant="plain">Skip</Button>

<Chip variant="soft" color="success">Active</Chip>
<Alert variant="outlined" color="warning">Check your input</Alert>
```

### Color System

Material UI: `primary`, `secondary`, `error`, `warning`, `info`, `success`
Joy UI: `primary`, `neutral`, `danger`, `success`, `warning`

```tsx
import Button from '@mui/joy/Button';
import Typography from '@mui/joy/Typography';

<Button color="primary">Primary</Button>
<Button color="neutral">Neutral</Button>
<Button color="danger">Delete</Button>
<Button color="success">Approve</Button>
<Button color="warning">Caution</Button>

<Typography color="danger">Error message</Typography>
```

### Component Naming Differences

| Material UI | Joy UI | Notes |
|-------------|--------|-------|
| `Paper` | `Sheet` | Surface container |
| `TextField` | `Input` / `Textarea` | Separate components, not a wrapper |
| `AppBar` | `Header` (custom) | Joy UI does not ship AppBar; use `Sheet` |
| `Snackbar` | `Snackbar` | Same name, different API |
| `Fab` | No equivalent | Use `IconButton` with `variant="solid"` |
| `Rating` | No equivalent | Not yet available in Joy UI |
| `SpeedDial` | No equivalent | Not yet available |

### Decoration Levels vs Elevation

Material UI uses `elevation={0..24}` for box-shadow depth. Joy UI uses CSS variables and the `shadow` prop:

```tsx
import Sheet from '@mui/joy/Sheet';

// Joy UI -- shadow levels
<Sheet variant="outlined" sx={{ p: 2 }}>No shadow</Sheet>
<Sheet variant="outlined" sx={{ p: 2, boxShadow: 'sm' }}>Small shadow</Sheet>
<Sheet variant="outlined" sx={{ p: 2, boxShadow: 'md' }}>Medium shadow</Sheet>
<Sheet variant="outlined" sx={{ p: 2, boxShadow: 'lg' }}>Large shadow</Sheet>
```

## Setup

### Basic Setup with CssVarsProvider

```tsx
// src/main.tsx
import { CssVarsProvider } from '@mui/joy/styles';
import CssBaseline from '@mui/joy/CssBaseline';
import App from './App';

function Root() {
  return (
    <CssVarsProvider>
      <CssBaseline />
      <App />
    </CssVarsProvider>
  );
}
```

`CssVarsProvider` replaces Material UI's `ThemeProvider`. It automatically:
- Injects CSS variables into `:root`
- Supports light/dark mode toggle without theme re-creation
- Enables runtime theme switching without JavaScript recalculation

### Dark Mode Toggle

```tsx
import { useColorScheme } from '@mui/joy/styles';
import IconButton from '@mui/joy/IconButton';

function ColorSchemeToggle() {
  const { mode, setMode } = useColorScheme();

  return (
    <IconButton
      variant="outlined"
      color="neutral"
      onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}
    >
      {mode === 'dark' ? <SunIcon /> : <MoonIcon />}
    </IconButton>
  );
}
```

No need to create separate light/dark themes. The CSS variables automatically switch.

## Theme Customization

### Using extendTheme

```tsx
import { CssVarsProvider, extendTheme } from '@mui/joy/styles';

const customTheme = extendTheme({
  colorSchemes: {
    light: {
      palette: {
        primary: {
          50: '#eff6ff',
          100: '#dbeafe',
          200: '#bfdbfe',
          300: '#93c5fd',
          400: '#60a5fa',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
          800: '#1e40af',
          900: '#1e3a8a',
        },
        success: {
          solidBg: '#16a34a',
          solidHoverBg: '#15803d',
        },
      },
    },
    dark: {
      palette: {
        primary: {
          solidBg: '#3b82f6',
          solidHoverBg: '#2563eb',
        },
      },
    },
  },
  fontFamily: {
    body: '"Inter", var(--joy-fontFamily-fallback)',
    display: '"Inter", var(--joy-fontFamily-fallback)',
  },
  typography: {
    h1: {
      fontSize: '2.25rem',
      fontWeight: 700,
      lineHeight: 1.2,
    },
    h2: {
      fontSize: '1.875rem',
      fontWeight: 600,
      lineHeight: 1.3,
    },
  },
  radius: {
    sm: '6px',
    md: '8px',
    lg: '12px',
  },
  components: {
    JoyButton: {
      styleOverrides: {
        root: {
          borderRadius: 'var(--joy-radius-md)',
          fontWeight: 600,
        },
      },
      defaultProps: {
        variant: 'solid',
        color: 'primary',
      },
    },
    JoyInput: {
      styleOverrides: {
        root: {
          '--Input-radius': 'var(--joy-radius-md)',
        },
      },
    },
  },
});

function App() {
  return (
    <CssVarsProvider theme={customTheme}>
      <CssBaseline />
      {/* app content */}
    </CssVarsProvider>
  );
}
```

### Accessing CSS Variables in Custom Components

```tsx
import { styled } from '@mui/joy/styles';

const CustomCard = styled('div')(({ theme }) => ({
  padding: theme.spacing(2),
  borderRadius: theme.vars.radius.md,
  backgroundColor: theme.vars.palette.background.surface,
  border: `1px solid ${theme.vars.palette.divider}`,
  boxShadow: theme.vars.shadow.sm,
  // CSS variables are also accessible as plain CSS
  // background: 'var(--joy-palette-background-surface)',
}));
```

### Custom Tokens

```tsx
const theme = extendTheme({
  colorSchemes: {
    light: {
      palette: {
        // Custom semantic tokens
        brand: {
          50: '#fdf2f8',
          500: '#ec4899',
          700: '#be185d',
        },
      },
    },
  },
});

// TypeScript: augment the palette interface
declare module '@mui/joy/styles' {
  interface PaletteRange {
    // already exists in Joy
  }
  interface Palette {
    brand: PaletteRange;
  }
}
```

## Component Examples

### Button

```tsx
import Button from '@mui/joy/Button';
import IconButton from '@mui/joy/IconButton';
import ButtonGroup from '@mui/joy/ButtonGroup';

// Variant
Files: 1
Size: 20.5 KB
Complexity: 28/100
Category: Design

Related in Design