# @dzbot/ui

The dzbot look for your own community website: the theme and the React components the dzbot web app is built with. Your site looks like your server's dzbot page, in your server's colour, and your players feel at home.

> **For dzbot Pro customers only.** This is not a free component library. You may use it only in sites and apps built for an organization with an active dzbot Pro subscription that work with dzbot. See [who may use it](#license).

## Who may use it

@dzbot/ui is source-available under the [dzbot UI License](https://developers.dzbot.de/ui/license), not open source. In short:

### You may

Use and change it in websites and apps built for an organization with an active dzbot Pro subscription — sites that use the dzbot API or SDK, or link to that organization's servers on dzbot.

### You may not

Use it for any other product, or redistribute or republish it on its own — as a component library, design system, UI kit or theme.

### When Pro ends

The right to use it ends with the subscription. Sites already running have 30 days to remove it.

The [dzbot terms of service](https://dzbot.de/terms-of-service) apply as well. The fonts are not part of the package and keep their own licenses (SIL Open Font License).

## Install

```
npm install @dzbot/ui lucide-react
```

Needs React 18 or newer and Tailwind CSS 4. Pairs with [@dzbot/sdk](https://developers.dzbot.de/sdk/) for your server's data and Sign in with dzbot.

## Theme

Three lines in your main stylesheet: the fonts first (a CSS `@import` has to come before every other rule), then Tailwind, then the theme.

```
@import "@dzbot/ui/fonts.css";
@import "tailwindcss";
@import "@dzbot/ui/theme.css";
```

`fonts.css` loads Bebas Neue, Barlow, Barlow Condensed and JetBrains Mono from Google Fonts; leave it out if you serve them yourself. `theme.css` brings the tokens, the dark base and the shapes, and registers the components with Tailwind (`@source "./dist"`) so their classes are generated. Tailwind skips `node_modules` on its own; if the classes are missing in your setup, name the package yourself, relative to your stylesheet:

```
@source "../node_modules/@dzbot/ui/dist";
```

| Token | Meaning |
| --- | --- |
| `accent-50` … `accent-950` | The server's colour — see [Colour](#colour) |
| `success`, `warning`, `danger`, `info` | Status: emerald, amber, red, sky. Never change with the palette |
| `medal-gold`, `medal-silver`, `medal-bronze` | Ranks 1–3 on leaderboards |
| `rounded-control`, `rounded-field`, `rounded-surface` | 2px, for buttons, fields and cards |
| `font-bebas` | Display: titles, big numbers |
| `font-mono-jb`, `hud-label` | Labels: JetBrains Mono, uppercase, wide tracking |
| `font-barlow`, `font-barlow-condensed` | Reading text; menus |

## Your server's colour

`accent-*` follows `data-palette` on `<html>` — the same palettes server owners pick for their dzbot page in Settings → General. To give one part of the page another server's colour, set it there together with `data-area="guest"`.

```
<html data-palette="teal"> <!-- amber (default), teal, cyan, fuchsia, lime, orange -->
<article data-area="guest" data-palette="lime">…</article>
```

## Router and language

Internal links (`TextLink to`, `NoticeAction to`) render a plain `<a href>` until you hand over your router's link. `UiProvider` also takes the label a button shows after its action succeeded, and how a failed action's error becomes text. Everything is optional.

```
import { Link } from 'react-router'
import { UiProvider } from '@dzbot/ui'

createRoot(root).render(
  <UiProvider link={Link} doneLabel="Saved" errorText={(error, fallback) => fallback ?? String(error)}>
    <App />
  </UiProvider>,
)
```

## Components

```
import { Button, Card, Stat } from '@dzbot/ui'

export function Wallet({ balance, onTopUp }: { balance: number; onTopUp: () => Promise<void> }) {
  return (
    <Card title="Wallet">
      <Stat label="Balance" value={balance} detail="shared by all servers" />
      <Button variant="primary" tone="tonal" action={onTopUp}>Top up</Button>
    </Card>
  )
}
```

| Component | Use | Main props |
| --- | --- | --- |
| `Button` | Every button. Outline first; `tone="tonal"` for one important button that stands alone. `action` takes an async function and shows pending, done and error itself | `variant` primary · secondary · danger · ghost · discord, `tone`, `size` sm · md · lg · icon, `action`, `doneLabel` |
| `IconButton` | An icon-only button; the label is its tooltip and screen-reader name | `label`, `tone` default · accent · danger, `size` |
| `Card` | The one surface, with an optional header bar. `Card.Inset` for a box inside it, `Card.Label` for a `// label` on the right | `title`, `aside`, `description`, `toolbar`, `flush`, `loading` |
| `Stat` | One number with its label, the top-left corner cut | `label`, `value`, `detail`, `tone`, `loading` |
| `Notice` | Callouts and banners; `NoticeAction` for its button | `tone` info · warning · danger · success · accent, `title`, `action`, `banner` |
| `StatusBadge` | A status: tinted, icon plus text, never colour alone | `tone` success · warning · danger · info · neutral · accent, `icon` |
| `Tag` | A neutral label (group, faction); `color` leads with a swatch. Never a status | `color`, `icon` |
| `Chip` | A filter chip | `selected` |
| `Facts`, `Fact` | Facts about one thing: mono label over its value, one to three columns | `columns`; `label`, `wide` |
| `Avatar` | A player's picture in the octagon, initials until it loads | `name`, `src`, `size`, `tone` |
| `IconOctagon` | The container for an icon | `size` xs – xl, `tone` |
| `SectionHeading`, `SubLabel` | A section title with a rule; a `// label` inside a card | `meta`, `as` |
| `TextLink` | A link in text, or on its own line with `standalone`; `href` opens a new tab | `to`, `href`, `standalone` |
| `Skeleton`, `LinesSkeleton`, `RowSkeleton` | Loading placeholders in the shape of the content | `className`; `lines`, `rows` |
| `BlockLoader` | The small busy marker: four blocks pulsing in turn | `size` |
| `cn`, `buttonVariants` | Join class names (later Tailwind classes win); a button's classes for a link that looks like one |  |

## Cut corner and octagon

The cut corner is dzbot's one signature shape: two opposite corners cut at 45°, or the top-left one on stat tiles. The border is drawn by the element, the surface by a layer 1px inside, so you set both colours as variables:

```
<div className="dz-cut p-4 [--dz-cut-border:var(--color-zinc-700)] [--dz-cut-fill:var(--color-zinc-900)]">…</div>
```

`dz-cut` cuts two corners (10px, `dz-cut-sm` 6px), `dz-cut-tl` the top-left one (12px), `dz-octagon` makes an octagon. Keep the cut corner rare: the lone call to action (`Button tone="tonal"`), `Stat` and dialogs.

## The rules of the look

Controls and labels speak the HUD of a game menu — square, JetBrains Mono, uppercase; what people read stays calm in Barlow. Buttons are outlines, never filled blocks; "selected" is the accent as tint, border or bar. Nothing glows, nothing is round (the octagon replaces the circle), and a status always shows icon and text, never colour alone — on an amber server, amber can't mean "pending".

---

Web page: https://developers.dzbot.de/ui/ · All pages: https://developers.dzbot.de/llms.txt
