# Attention

> A short, domain-independent list of things the user should act on now (unread conversations, failed deployments, approvals, setup steps), ordered by urgency.

Source: https://docs.nasaqui.com/components/attention

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/attention.json
```

Answers one question on an overview page: **what needs me now?** Products supply the items: unread
conversations, deals that need a follow-up, failed deployments, issues waiting for approval, remaining setup
steps. Attention orders them by urgency, trims the list, and presents each as one calm row with an optional
action. It holds no business logic and knows nothing about any product.

## When to use

- At the top of a product's home or overview page, above metrics and activity.
- For a setup checklist on a new workspace (give every item `done`).
- Across products in a hub, marking each row with its `ProductMark`.

## When not to use

- A full notification feed or inbox: use `NotificationItem` rows in a sheet or page.
- Informational activity ("Sara commented"): if the user cannot act on it, it does not belong here.
- A system-wide banner (outage, billing lock): that is page-level, not a list row.
- Filler. With nothing to act on, the section disappears; don't add a placeholder card.

## Import

```tsx
import { Attention, type AttentionItem } from "@fadymondy/nasaq/web";
```

## Quick start

```tsx
const items: AttentionItem[] = [
  { id: "deploy", tone: "danger", title: "Riyadh Storefront deployment failed", time: "12m", href: "/deploys/91",
    action: { label: "Retry", onClick: retry } },
  { id: "approve", tone: "warning", title: "MH-721 is waiting for your approval", href: "/issues/MH-721" },
  { id: "inbox", tone: "info", icon: MessageSquare, title: "Unread conversations", count: 4, href: "/inbox" },
];

<Attention items={items} viewAllHref="/inbox" />;
```

## Anatomy

```
section [data-slot=attention]
├─ header: h2 title · open count (or checklist progress) · "View all"
├─ ul (line-separated, no card)
│  └─ li [data-slot=attention-item, data-tone, data-done]
│     ├─ tone shape or custom icon
│     ├─ title (link/button stretched over the row) + one-line description
│     ├─ count · <time>
│     ├─ action button (secondary, sm)
│     └─ dismiss × (on hover / focus / touch)
└─ "Show N more" toggle (when no "View all" target)
```

## API

### `Attention`

| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| `items` | `AttentionItem[]` | required | Supplied by the product. |
| `title` | `ReactNode` | "Needs your attention" / "يحتاج انتباهك" | Section heading. |
| `headingLevel` | `2 \| 3 \| 4` | `2` | Match the page outline. |
| `max` | `number` | `5` | Rows before "Show more" or "View all". |
| `sort` | `boolean` | `true` | Danger → warning → info → neutral, stable within a tone. Checklists keep host order. Done rows always last. |
| `viewAllHref` / `onViewAll` | `string` / `() => void` | — | Adds "View all" in the header and replaces the in-place "Show more". |
| `empty` | `ReactNode` | `null` | `null` removes the whole section when there are no items. |
| `loading` | `boolean` | `false` | Placeholder rows, `aria-busy`. |
| `labels` | `Partial<…>` | locale strings | `title`, `showMore(n)`, `showLess`, `viewAll`, `dismiss`, `done`, `progress(done, total)`, `loading`. |

Plus any `<section>` prop.

### `AttentionItem`

| Field | Type | Notes |
| --- | --- | --- |
| `id` | `string` | Stable key. |
| `title` | `ReactNode` | A short sentence of what needs doing. |
| `description` | `ReactNode` | One line of context, truncated. |
| `tone` | `"danger" \| "warning" \| "info" \| "neutral"` | Default `neutral`. Each tone has its own shape (CircleX, CircleAlert, CircleDot, Circle). |
| `icon` | `LucideIcon \| ReactElement` | Replaces the tone shape (e.g. `<ProductMark brand="mahaam" size={16} title="" />`). |
| `count` | `number` | How many things the row stands for. |
| `time` / `dateTime` | `ReactNode` / `string` | Pre-formatted relative time and its machine value. |
| `href` / `onSelect` | `string` / `() => void` | Makes the whole row a link or button. |
| `action` | `{ label, href?, onClick? }` | An explicit action at the inline end. Hidden once `done`. |
| `done` | `boolean` | Checklist step state. Set it on every item to switch on checklist mode. |
| `onDismiss` | `() => void` | Shows a dismiss button; the host removes the item. |

### `AttentionRow`

One row, for hosts that build their own list: `item`, `dismissLabel`, `doneLabel`, plus `<li>` props.

## Examples

**Setup checklist.** Every item has `done`, so the header shows "2 of 4 done" with a thin bar, rows keep
host order, and finished steps drop to the end with a check and muted text (no strike-through: it cuts through Arabic dots).

```tsx
<Attention
  title="Finish setting up"
  items={steps.map((s) => ({ ...s, done: completed.has(s.id), action: { label: "Start", href: s.href } }))}
/>
```

**Across products.** Mark each row with its product; urgency still sorts the list.

```tsx
<Attention max={3} items={[{ id: "a", icon: <ProductMark brand="zekra" size={16} title="" />, tone: "danger", title: "Data source sync failed", href: "…" }]} />
```

**Empty.** By default the section renders nothing. Pass `empty` only where absence would confuse:
`<Attention items={[]} empty="Nothing needs your attention right now." />`.

## Accessibility

- A `<section>` labelled by its heading. Rows are a `<ul>`.
- The row is clickable through a stretched title link or button (`::after` overlay), so there is no nested
  interactive content. The action and dismiss buttons are separate tab stops above the overlay.
- Urgency is never colour alone: each tone has its own icon shape. Done rows add a visually hidden "Done".
- Dismiss is hidden until hover, but visible on keyboard focus and always visible on touch (`pointer: coarse`).
- `aria-expanded` on "Show more"; `aria-busy` while loading.

## RTL & i18n

All default strings are English or Arabic by the provider locale; override any with `labels`. Layout uses
logical properties only, so rows mirror in RTL. Counts and times use tabular numerals. Pass times already
formatted for the locale.

## Styling & tokens

No card: a heading on the surface and `border-border` line separators (LAYOUT.md). Rows are `min-h-row`,
hover `bg-nq-hover`, focus ring `nq-focus`. Tone colours: `text-nq-{danger,warning,info}-text`. Progress bar:
`bg-nq-surface-soft` track, `bg-nq-success` fill. `className` merges onto the section.

## Do / Don't

- Do keep it to things the user can act on, phrased as what needs doing.
- Do keep `max` small (3–5); link to the full inbox with `viewAllHref`.
- Don't wrap it in a card or put it in a card grid.
- Don't show an "all clear" box by default; the empty section disappears.
- Don't use it for metrics; that is a KPI card.

## Related

`status` (same tone shapes), `notification-item` (full feeds), `button`, `product-mark`.

## Lab

https://docs.nasaqui.com/?path=/docs/components-alerts-notifications-attention--docs

## Code

### React

```tsx
const items: AttentionItem[] = [
  { id: "deploy", tone: "danger", title: "Riyadh Storefront deployment failed", time: "12m", href: "/deploys/91",
    action: { label: "Retry", onClick: retry } },
  { id: "approve", tone: "warning", title: "MH-721 is waiting for your approval", href: "/issues/MH-721" },
  { id: "inbox", tone: "info", icon: MessageSquare, title: "Unread conversations", count: 4, href: "/inbox" },
];

<Attention items={items} viewAllHref="/inbox" />;
```

### shadcn

```tsx
const items: AttentionItem[] = [
  { id: "deploy", tone: "danger", title: "Riyadh Storefront deployment failed", time: "12m", href: "/deploys/91",
    action: { label: "Retry", onClick: retry } },
  { id: "approve", tone: "warning", title: "MH-721 is waiting for your approval", href: "/issues/MH-721" },
  { id: "inbox", tone: "info", icon: MessageSquare, title: "Unread conversations", count: 4, href: "/inbox" },
];

<Attention items={items} viewAllHref="/inbox" />;
```

### Vue

```vue
<script setup lang="ts">
import { MessageSquare } from "lucide-vue-next";
import { NqAttention, type AttentionItem } from "@fadymondy/nasaq/vue";

const retry = () => {};

const items: AttentionItem[] = [
  { id: "deploy", tone: "danger", title: "Riyadh Storefront deployment failed", time: "12m", href: "/deploys/91",
    action: { label: "Retry", onClick: retry } },
  { id: "approve", tone: "warning", title: "MH-721 is waiting for your approval", href: "/issues/MH-721" },
  { id: "inbox", tone: "info", icon: MessageSquare, title: "Unread conversations", count: 4, href: "/inbox" },
];
</script>

<template>
  <NqAttention :items="items" view-all-href="/inbox" />
</template>
```

### Blade

```blade
<x-nq::attention :max="2" :items="[
    ['id' => 'deploy', 'tone' => 'danger', 'title' => 'Riyadh Storefront deployment failed', 'time' => '12m', 'href' => '/deploys/91',
        'action' => ['label' => 'Retry', 'href' => '/deploys/91/retry'], 'dismissible' => true],
    ['id' => 'approve', 'tone' => 'warning', 'title' => 'MH-721 is waiting for your approval', 'href' => '/issues/MH-721'],
    ['id' => 'inbox', 'tone' => 'info', 'icon' => 'message-square', 'title' => 'Unread conversations', 'count' => 4, 'href' => '/inbox'],
    ['id' => 'invoice', 'tone' => 'neutral', 'title' => 'Invoice INV-204 is due in 3 days', 'href' => '/invoices/204'],
]" />
```

### HTML + Alpine

```html
<section data-slot="attention" aria-labelledby="nq-attention-1cda9c01"     x-data="nqAttention(2, 4)"
    class="flex flex-col">
    <header class="flex min-h-control items-center gap-2 pb-2">
        <h2 id="nq-attention-1cda9c01" class="text-label text-foreground">Needs your attention</h2>
                    <span data-slot="attention-count" x-text="total" class="text-caption text-muted-foreground tabular-nums">4</span>
                            </header>
            <ul class="flex flex-col border-t border-border">
                            <li data-slot="attention-item" data-tone="danger"  data-id="deploy"
        class="group/attention relative flex min-h-row items-center gap-3 border-b border-border px-1 py-2 transition-colors duration-150 ease-nq hover:bg-nq-hover">
    <span class="relative flex size-5 shrink-0 items-center justify-center [&>svg]:size-4">
                    <svg aria-hidden="true" class="size-4 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>                    </span>
    <span class="flex min-w-0 flex-1 flex-col">
                    <a href="/deploys/91" class="min-w-0 truncate text-body-sm text-start outline-none text-foreground after:absolute after:inset-0 after:rounded-control focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-nq-focus">Riyadh Storefront deployment failed</a>
                            </span>
                <time  class="shrink-0 text-caption text-muted-foreground tabular-nums">12m</time>
                            <a href="/deploys/91/retry" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5 relative z-10">Retry</a>
                        <button data-slot="button"
     type="button"                         aria-label="Dismiss" x-on:click="dismiss($el.closest(&#039;li&#039;))" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 hover:bg-nq-hover size-control-sm p-0 relative z-10 text-muted-foreground opacity-0 group-hover/attention:opacity-100 focus-visible:opacity-100 pointer-coarse:opacity-100 [&_svg]:size-3.5">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
    </li>
                            <li data-slot="attention-item" data-tone="warning"  data-id="approve"
        class="group/attention relative flex min-h-row items-center gap-3 border-b border-border px-1 py-2 transition-colors duration-150 ease-nq hover:bg-nq-hover">
    <span class="relative flex size-5 shrink-0 items-center justify-center [&>svg]:size-4">
                    <svg aria-hidden="true" class="size-4 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>                    </span>
    <span class="flex min-w-0 flex-1 flex-col">
                    <a href="/issues/MH-721" class="min-w-0 truncate text-body-sm text-start outline-none text-foreground after:absolute after:inset-0 after:rounded-control focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-nq-focus">MH-721 is waiting for your approval</a>
                            </span>
                </li>
                            <li data-slot="attention-item" data-tone="info"  data-id="inbox"
     style="display: none"     class="group/attention relative flex min-h-row items-center gap-3 border-b border-border px-1 py-2 transition-colors duration-150 ease-nq hover:bg-nq-hover">
    <span class="relative flex size-5 shrink-0 items-center justify-center [&>svg]:size-4">
                    <svg aria-hidden="true" class="size-4 text-nq-info-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"/>
</svg>                            <span data-slot="attention-tone" class="absolute -end-1 -bottom-1 flex rounded-full bg-background">
                <svg aria-hidden="true" stroke-width="3" class="size-2.5 text-nq-info-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <circle cx="12" cy="12" r="1"/>
</svg>            </span>
            </span>
    <span class="flex min-w-0 flex-1 flex-col">
                    <a href="/inbox" class="min-w-0 truncate text-body-sm text-start outline-none text-foreground after:absolute after:inset-0 after:rounded-control focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-nq-focus">Unread conversations</a>
                            </span>
            <span data-slot="attention-item-count" class="shrink-0 rounded-full border border-border px-1.5 text-caption text-foreground tabular-nums">4</span>
                </li>
                            <li data-slot="attention-item" data-tone="neutral"  data-id="invoice"
     style="display: none"     class="group/attention relative flex min-h-row items-center gap-3 border-b border-border px-1 py-2 transition-colors duration-150 ease-nq hover:bg-nq-hover">
    <span class="relative flex size-5 shrink-0 items-center justify-center [&>svg]:size-4">
                    <svg aria-hidden="true" class="size-4 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
</svg>                    </span>
    <span class="flex min-w-0 flex-1 flex-col">
                    <a href="/invoices/204" class="min-w-0 truncate text-body-sm text-start outline-none text-foreground after:absolute after:inset-0 after:rounded-control focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-nq-focus">Invoice INV-204 is due in 3 days</a>
                            </span>
                </li>
                    </ul>
            <button type="button" aria-expanded="false" :aria-expanded="expanded" x-on:click="toggle()"
            data-more="Show {n} more" data-less="Show less"
            x-text="expanded ? $el.dataset.less : $el.dataset.more.replace('{n}', hidden)"
            class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 hover:bg-nq-hover h-control-sm px-2.5 mt-1 self-start text-muted-foreground">Show 2 more</button>
    </section>
```
