# State

> An illustration, a title, an optional description and optional actions for empty, error and informational states.

Source: /docs/components/state

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

## Basic state

`illustration` sits in a 180px square box. `title` uses the h3 semi-bold style and `description` the body medium style, centred below it. `actions` renders under the messages. The column is up to 348px wide with 32px between the content and the actions.

```tsx
import { Button, State } from '@aksornproject/aksara-ui'

export default function StateBasic() {
  return (
    <State
      illustration={
        <img
          src="/assets/images/states/no-saved-courses.webp"
          alt=""
          className="h-full w-full object-contain"
        />
      }
      title="No saved courses"
      description="Courses you save will appear here for easy access."
      actions={
        <div className="flex justify-center">
          <Button>Browse courses</Button>
        </div>
      }
    />
  )
}
```

## Actions

`actions` takes any node. Lay out several buttons in your own row, so you choose the order, gap and alignment. The column is 348px wide at most, so let a row of long labels wrap with `flex-wrap`.

```tsx
import { Button, State } from '@aksornproject/aksara-ui'

export default function StateActions() {
  return (
    <State
      illustration={
        <img
          src="/assets/images/states/course-access-expired.webp"
          alt=""
          className="h-full w-full object-contain"
        />
      }
      title="Access expired"
      description="Your access to this course has expired. Please renew to continue learning."
      actions={
        <div className="flex flex-wrap justify-center gap-spacing-8">
          <Button>Renew access</Button>
          <Button variant="secondary-brand">Explore other courses</Button>
        </div>
      }
    />
  )
}
```

## Title only

Leave out `description`, or pass an empty string, and the messages hold only the title.

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

export default function StateTitleOnly() {
  return (
    <State
      illustration={
        <img
          src="/assets/images/states/empty-file.webp"
          alt=""
          className="h-full w-full object-contain"
        />
      }
      title="Nothing to show"
    />
  )
}
```

## Custom styles

`className` merges last into the root, so a wider `max-w-*` or a different gap wins. `contentWrapperClassName`, `illustrationWrapperClassName` and `messagesWrapperClassName` reach the inner boxes. `messagesClassNames` takes `title` and `description` classes.

```tsx
import { Button, State } from '@aksornproject/aksara-ui'

export default function StateCustom() {
  return (
    <State
      className="max-w-spacing-480 gap-y-spacing-16"
      illustrationWrapperClassName="size-spacing-120"
      messagesClassNames={{ description: 'text-color-text-tertiary' }}
      illustration={
        <img
          src="/assets/images/states/slower-than-usual-connection.webp"
          alt=""
          className="h-full w-full object-contain"
        />
      }
      title="Connection is slow"
      description="Your connection seems slower than usual. Please check your internet and try again."
      actions={
        <div className="flex justify-center">
          <Button size="sm">Try again</Button>
        </div>
      }
    />
  )
}
```

## Accessibility

- The title is a `p`, so it never breaks the page's heading outline. When State replaces a whole section, keep a heading of the right level in the page or label the region with `aria-labelledby`.
- Give a decorative illustration an empty `alt`. Describe it only when it adds information the title does not.
- When State replaces results after a search or filter, put it in a live region so screen reader users hear the change.

## API

| Prop | Type | Description |
| --- | --- | --- |
| `title` (required) | `string` | The heading line, in the h3 semi-bold style inside a `p`. |
| `illustration` (required) | `ReactNode` | Node in the 180px box above the messages, usually an `img`. |
| `description` | `string` | Supporting text below the title. Omitted when empty. |
| `actions` | `ReactNode` | Node below the messages, such as a row of buttons. |
| `contentWrapperClassName` | `string` | Classes for the box that holds the illustration and messages. |
| `illustrationWrapperClassName` | `string` | Classes for the 180px illustration box. |
| `messagesWrapperClassName` | `string` | Classes for the box that holds the title and description. |
| `messagesClassNames` | `{ title?: string; description?: string; }` | Classes merged last into the title and description. |