# Info Tile

A tile with an icon, a label and a value for one fact about a record.

```tsx
import { InfoTile, StatusBadge } from 'ferry-ui'
import { CreditCard, Globe, ShieldCheck, User } from 'lucide-react'

export default function InfoTileHero() {
  return (
    <div className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
      <InfoTile icon={<ShieldCheck />} label="Status" value={<StatusBadge tone="success" label="Active" />} />
      <InfoTile icon={<CreditCard />} label="Plan" value="Pro" hint="Renews on Nov 1, 2026" />
      <InfoTile icon={<User />} label="Owner" value="Maya Chen" hint="maya@example.com" />
      <InfoTile icon={<Globe />} label="Timezone" value="Europe/Paris" />
    </div>
  )
}
```

## Usage guidelines

- **Key facts at the top of a page.** Use a grid of tiles for the status, the plan or the owner of a record.
- **A number to compare is a metric.** For a KPI, use [Metric Card](/docs/components/metric-card).
- **Many facts are a list.** For a long list of labels and values, use [Description List](/docs/components/description-list).

## Anatomy

Import the component. A tile has one part and no border.

```tsx title="Anatomy"

<InfoTile icon={<Icon />} label="" value="" hint="" />
```

Put the tiles in a grid, for example `grid gap-x-8 gap-y-6 sm:grid-cols-2`.

## Examples

### Hint

`hint` adds a second line below the value.

```tsx
import { InfoTile } from 'ferry-ui'
import { CalendarDays, CreditCard } from 'lucide-react'

export default function InfoTileHint() {
  return (
    <div className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
      <InfoTile icon={<CreditCard />} label="Plan" value="Pro" hint="8 of 10 seats used" />
      <InfoTile icon={<CalendarDays />} label="Next invoice" value="Nov 1, 2026" />
    </div>
  )
}
```

### No icon

`icon` is optional. A tile with no icon shows only the text.

```tsx
import { InfoTile } from 'ferry-ui'

export default function InfoTileNoIcon() {
  return <InfoTile label="Billing email" value="billing@example.com" hint="The invoices go to this address." />
}
```

### Element as value

`value` accepts an element. Use it for a [Status](/docs/components/status), a link or a value with a [Copy](/docs/components/copy) button.

```tsx
import { CopyButton, InfoTile, StatusBadge } from 'ferry-ui'
import { Activity, Fingerprint } from 'lucide-react'

const WORKSPACE_ID = 'ws_8f3a21c9e04b'

export default function InfoTileValueElement() {
  return (
    <div className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
      <InfoTile
        icon={<Activity />}
        label="Status"
        value={<StatusBadge tone="info" label="Syncing" pulse />}
        hint="Started 2 minutes ago"
      />
      <InfoTile
        icon={<Fingerprint />}
        label="Workspace ID"
        value={
          <span className="flex min-w-0 items-center gap-2">
            <span className="truncate font-mono text-sm">{WORKSPACE_ID}</span>
            <CopyButton value={WORKSPACE_ID} what="workspace ID" variant="ghost" />
          </span>
        }
      />
    </div>
  )
}
```

### Long value

The value and the hint stay on one line. The tile cuts a long text. Give the full text in a `title` attribute.

```tsx
import { InfoTile } from 'ferry-ui'
import { Globe } from 'lucide-react'

const WEBSITE = 'www.acme-customer-portal.example.com'

export default function InfoTileLongValue() {
  return (
    <InfoTile
      className="w-full max-w-xs"
      icon={<Globe />}
      label="Website"
      value={<span title={WEBSITE}>{WEBSITE}</span>}
      hint="This address shows on each invoice and in each email to a customer."
    />
  )
}
```

### Loading

Set `loading` while the value loads. The tile shows a skeleton, hides the hint and sets `aria-busy`.

```tsx
import * as React from 'react'
import { InfoTile, Label, Switch } from 'ferry-ui'
import { CalendarDays, User } from 'lucide-react'

export default function InfoTileLoading() {
  // In an app, `loading` comes from the request that loads the record.
  const [loading, setLoading] = React.useState(true)

  return (
    <div className="flex flex-col gap-5">
      <div className="flex items-center gap-2">
        <Switch id="tiles-loading" checked={loading} onCheckedChange={setLoading} />
        <Label htmlFor="tiles-loading">Loading</Label>
      </div>
      <div className="grid gap-x-8 gap-y-6 sm:grid-cols-2">
        <InfoTile icon={<User />} label="Owner" value="Maya Chen" hint="maya@example.com" loading={loading} />
        <InfoTile icon={<CalendarDays />} label="Next invoice" value="Nov 1, 2026" loading={loading} />
      </div>
    </div>
  )
}
```

## Accessibility

- The icon is decorative. Screen readers do not read it.
- The label must give the meaning of the value without the icon.

## API reference

`InfoTile` also accepts each attribute of the `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` (required) | `ReactNode` |  | Short caption rendered as a `MonoLabel` (1–3 words: "Plan", "Owner", "Timezone"). |
| `icon` | `ReactNode` |  | Icon shown in an `xl` `IconBox` on the left (sized to 20px automatically). Omit for a text-only tile. |
| `value` | `ReactNode` |  | Main value. Plain text, or a small inline node (badge, link, value + copy button). Truncated to one line: add a `title` on long text. Can be omitted while `loading`. |
| `hint` | `ReactNode` |  | Optional secondary line under the value ("Renews on May 4", "of 10 seats"). Truncated to one line. |
| `loading` | `boolean` | `false` | Shows a skeleton instead of the value, hides the hint and sets `aria-busy`. |
