# Badge

> Badges are single-line labels for a status, a category or a count.

Source: /docs/components/badge

```tsx
import { Badge, BadgeDot } from '@aksornproject/aksara-ui'
```

## Status colours

`color` sets the muted status colour. `white` is the default. `pending` and `rejected` sit beside the usual status roles.

```tsx
import { Badge } from '@aksornproject/aksara-ui'

export default function BadgeStatus() {
  return (
    <>
      <Badge>Draft</Badge>
      <Badge color="grey">Archived</Badge>
      <Badge color="brand">Featured</Badge>
      <Badge color="information">In review</Badge>
      <Badge color="success">Active</Badge>
      <Badge color="warning">Due soon</Badge>
      <Badge color="error">Overdue</Badge>
      <Badge color="pending">Pending</Badge>
      <Badge color="rejected">Rejected</Badge>
    </>
  )
}
```

## Utility hues

Fifteen muted hues tag subjects, categories and labels. Do not use them for status. They space the slots 4px apart instead of 2px.

```tsx
import { Badge } from '@aksornproject/aksara-ui'

export default function BadgeUtility() {
  return (
    <>
      <Badge color="teal">Science</Badge>
      <Badge color="indigo">Mathematics</Badge>
      <Badge color="amber">History</Badge>
      <Badge color="pink">Art</Badge>
      <Badge color="deep-purple">Music</Badge>
      <Badge color="light-green">Biology</Badge>
      <Badge color="blue-grey">Elective</Badge>
    </>
  )
}
```

## Solid

`variant="solid"` gives a high-emphasis badge in one of seven status colours. `brand` is its default. TypeScript rejects a utility hue on a solid badge.

```tsx
import { Badge } from '@aksornproject/aksara-ui'

export default function BadgeSolid() {
  return (
    <>
      <Badge variant="solid">New</Badge>
      <Badge variant="solid" color="information">
        Live
      </Badge>
      <Badge variant="solid" color="success">
        Passed
      </Badge>
      <Badge variant="solid" color="warning">
        At risk
      </Badge>
      <Badge variant="solid" color="error">
        Failed
      </Badge>
    </>
  )
}
```

## Sizes and shape

Four sizes, 24, 28, 32 and 36px high. `medium` is the default. Every size uses the same 16px label style, so only the height and padding change. `type="pill"` rounds the corners fully.

```tsx
import { Badge } from '@aksornproject/aksara-ui'

export default function BadgeSizes() {
  return (
    <>
      <Badge size="small" color="brand">
        Small
      </Badge>
      <Badge size="medium" color="brand">
        Medium
      </Badge>
      <Badge size="large" color="brand">
        Large
      </Badge>
      <Badge size="xlarge" color="brand">
        Extra large
      </Badge>
      <Badge size="large" color="brand" type="pill">
        Pill
      </Badge>
    </>
  )
}
```

## Slots

`leadingIcon` and `trailingIcon` render in 16px slots. A single element becomes the slot itself and its own `className` wins. A function receives the slot props and the Badge state, and must spread the props onto the element it returns.

`BadgeDot` is the default slot content, an 8px dot in a 16px box that takes the text colour.

```tsx
import { IconInterfaceEssentialDoneCheck } from '@aksornproject/aksara-icons'
import { Badge, BadgeDot } from '@aksornproject/aksara-ui'

export default function BadgeSlots() {
  return (
    <>
      <Badge color="success" leadingIcon={<BadgeDot />}>
        Online
      </Badge>
      <Badge
        color="information"
        leadingIcon={<IconInterfaceEssentialDoneCheck aria-hidden />}
      >
        Submitted
      </Badge>
      <Badge
        color="pending"
        size="large"
        trailingIcon={(props, state) => (
          <span {...props} aria-hidden>
            {state.size === 'large' ? '›' : '>'}
          </span>
        )}
      >
        Next lesson
      </Badge>
    </>
  )
}
```

## Icon only

`iconOnly` renders a square badge with no label. A `leadingIcon` replaces the children. Without one, the children render in the icon slot. The trailing slot and the notification dot are hidden.

```tsx
import { IconInterfaceEssentialDoneCheck } from '@aksornproject/aksara-icons'
import { Badge, BadgeDot } from '@aksornproject/aksara-ui'

export default function BadgeIconOnly() {
  return (
    <>
      <Badge
        iconOnly
        color="success"
        aria-label="Verified"
        leadingIcon={<IconInterfaceEssentialDoneCheck />}
      />
      <Badge iconOnly variant="solid" aria-label="New">
        <BadgeDot />
      </Badge>
    </>
  )
}
```

## Loading

`loading` shows the skeleton fill and keeps the content in the DOM at opacity 0, so the badge keeps its loaded width. It sets `aria-busy`.

```tsx
import { Badge, BadgeDot } from '@aksornproject/aksara-ui'

export default function BadgeLoading() {
  return (
    <>
      <Badge loading>Active</Badge>
      <Badge loading size="large" leadingIcon={<BadgeDot />}>
        In review
      </Badge>
    </>
  )
}
```

## Notification dot

`showNotificationDot` puts a dot before the label in its own wrapper. `customNotificationDot` replaces the dot and `dotWrapperClassName` styles the wrapper.

```tsx
import { Badge } from '@aksornproject/aksara-ui'

export default function BadgeNotificationDot() {
  return (
    <>
      <Badge color="error" showNotificationDot>
        3 new
      </Badge>
      <Badge
        color="brand"
        showNotificationDot
        customNotificationDot={<span aria-hidden>★</span>}
      >
        Featured
      </Badge>
    </>
  )
}
```

## Composition

`render` swaps the `span` for another element and keeps the Badge classes. `className` merges last. Labels longer than 280px end in an ellipsis.

```tsx
import { Badge } from '@aksornproject/aksara-ui'

export default function BadgeRender() {
  return (
    <Badge color="information" render={<a href="#render" />}>
      View report
    </Badge>
  )
}
```

## Accessibility

- The Badge is a plain `span` with no role. Put the meaning in the label, not only in the colour.
- An icon-only Badge has no visible label. Give it an `aria-label`, or hide it with `aria-hidden` when nearby text says the same.
- `BadgeDot` and the default notification dot are `aria-hidden`.
- `loading` sets `aria-busy` and keeps the content in the DOM.

## API

### Badge

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ComponentRenderFn<HTMLProps, {}> \| ReactElement<unknown, string \| React.JSXElementConstructor<any>>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
| `variant` | `"muted" \| "solid"` |  | Defaults to `'muted'`. |
| `color` | `"amber" \| "blue-grey" \| "brand" \| "brown" \| "cyan" \| "deep-orange" \| "deep-purple" \| "error" \| "green" \| "grey" \| "indigo" \| "information" \| "light-blue" \| "light-green" \| "lime" \| "orange" \| "pending" \| "pink" \| "purple" \| "rejected" \| "success" \| "teal" \| "warning" \| "white"` |  | Defaults to `'white'`. Defaults to `'brand'`. |
| `size` | `"large" \| "medium" \| "small" \| "xlarge"` | `'medium'` | Height 24, 28, 32 or 36px. |
| `type` | `"box" \| "pill"` | `'box'` | Box corners or a fully rounded pill. |
| `iconOnly` | `boolean` | `false` | Renders a square badge with no label. A `leadingIcon` replaces the children; without one, the children render inside the icon slot. The trailing icon and the notification dot are hidden. |
| `loading` | `boolean` | `false` | Shows the skeleton fill and hides the content, keeping its width. |
| `leadingIcon` | `BadgeSlot` |  | Content of the 16px slot before the label. |
| `trailingIcon` | `BadgeSlot` |  | Content of the 16px slot after the label. Hidden when `iconOnly` is set. |
| `showNotificationDot` | `boolean` |  | Shows a dot before the label. Hidden when `iconOnly` is set. |
| `customNotificationDot` | `ReactNode` |  | Replaces the default `BadgeDot` when `showNotificationDot` is set. |
| `dotWrapperClassName` | `string` |  | Classes for the span that wraps the notification dot and the label. |
| `className` | `string` |  | Merged last with `cn()`, so these classes win. |

### BadgeDot

`BadgeDot` takes the attributes of an `svg`. `className` merges last with `cn()`.