# Infolist

> A read-only description list for a record's detail page, turning enum and boolean values into badges, with links, copy buttons, sections, and a column layout.

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

## Install

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

The read side of a form. `Infolist` shows a record as label and value pairs. An `enum` value becomes a coloured
badge, a `boolean` becomes a Yes or No badge, emails, phone numbers and links are clickable, ids can be copied, and a
missing value says "Not set" instead of leaving a hole.

## When to use

- The detail page of a customer, order, device or any record.
- The read-only twin of a [SchemaForm](https://docs.nasaqui.com/components/schema-form).

## When not to use

- Rows of many records: use a table.
- Editing in place: use a form.

## Import

```tsx
import { Infolist } from "@fadymondy/nasaq/web";
```

## Quick start

```tsx
<Infolist
  columns={2}
  items={[
    { id: "name", label: "Name", labelAr: "الاسم", value: "Acme Trading" },
    { id: "status", label: "Status", labelAr: "الحالة", type: "enum", value: "active", options: { active: { label: "Active", labelAr: "نشط", variant: "success" } } },
    { id: "vip", label: "VIP", labelAr: "مميز", type: "boolean", value: true },
    { id: "email", label: "Email", type: "email", value: "hello@acme.test", copyable: true },
  ]}
/>
```

## Anatomy

```
Infolist                 data-slot="infolist"  role="group"
└─ section               one per group, with a heading
   └─ dl
      └─ div             data-slot="infolist-item"
         ├─ dt           label
         └─ dd           value, and a copy button
```

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `InfolistItem[]` | none | Flat rows. |
| `sections` | `InfolistSection[]` | none | Groups with `title`, `titleAr`, `description` and `items`. |
| `columns` | `1 \| 2 \| 3` | `2` | From the small breakpoint up; one column on a phone. |
| `layout` | `"stacked" \| "inline"` | `stacked` | Label above the value, or label and value on one line. |
| `showEmpty` | `boolean` | `true` | `false` hides rows without a value. |
| `label`, `locale`, `labels`, `className` | | | |

`InfolistItem`: `id`, `label`, `labelAr`, `value`, `type` (`text`, `number`, `date`, `datetime`, `boolean`, `enum`,
`email`, `url`, `tel`, `code`, `list`), `options` (for `enum` and `list`: `label`, `labelAr`, `variant`, `icon`),
`copyable`, `unit`, `wide`, `render`, `hint`, `hintAr`.

## Accessibility

- It is a real description list (`dl`, `dt`, `dd`), so a screen reader pairs each label with its value.
- Badges carry words and an icon; the colour only backs them up.
- Links open in a new tab with `noopener`; only `http` and `https` are linked.

## RTL & i18n

- Labels use `labelAr`; values that are code, emails, phone numbers and URLs stay left to right.
- Free text is isolated with `bdi dir="auto"`. Numbers and dates use Latin digits.

## Styling & tokens

Badge variants and text tokens. Extend with `className`.

## Do / Don't

- Do give enum values a `variant` so status reads at a glance.
- Do mark ids and codes `copyable`.
- Do not put actions in the values; put them in the page header.

## Related

- [SchemaForm](https://docs.nasaqui.com/components/schema-form)
- [RelationPicker](https://docs.nasaqui.com/components/relation-picker)

## Lab

https://docs.nasaqui.com/?path=/docs/components-data-display-infolist--docs

## Code

### React

```tsx
<Infolist
  columns={2}
  items={[
    { id: "name", label: "Name", labelAr: "الاسم", value: "Acme Trading" },
    { id: "status", label: "Status", labelAr: "الحالة", type: "enum", value: "active", options: { active: { label: "Active", labelAr: "نشط", variant: "success" } } },
    { id: "vip", label: "VIP", labelAr: "مميز", type: "boolean", value: true },
    { id: "email", label: "Email", type: "email", value: "hello@acme.test", copyable: true },
  ]}
/>
```

### shadcn

```tsx
<Infolist
  columns={2}
  items={[
    { id: "name", label: "Name", labelAr: "الاسم", value: "Acme Trading" },
    { id: "status", label: "Status", labelAr: "الحالة", type: "enum", value: "active", options: { active: { label: "Active", labelAr: "نشط", variant: "success" } } },
    { id: "vip", label: "VIP", labelAr: "مميز", type: "boolean", value: true },
    { id: "email", label: "Email", type: "email", value: "hello@acme.test", copyable: true },
  ]}
/>
```

### Vue

```vue
<script setup lang="ts">
import { NqInfolist } from "@fadymondy/nasaq/vue";

const items = [
  { id: "name", label: "Name", labelAr: "الاسم", value: "Acme Trading" },
  { id: "status", label: "Status", labelAr: "الحالة", type: "enum", value: "active", options: { active: { label: "Active", labelAr: "نشط", variant: "success" } } },
  { id: "vip", label: "VIP", labelAr: "مميز", type: "boolean", value: true },
  { id: "email", label: "Email", type: "email", value: "hello@acme.test", copyable: true },
] as const;
</script>

<template>
  <NqInfolist :columns="2" :items="items" />
</template>
```

### Blade

```blade
<x-nq::infolist
    :columns="2"
    :items="[
        ['id' => 'name', 'label' => 'Name', 'labelAr' => 'الاسم', 'value' => 'Acme Trading'],
        ['id' => 'status', 'label' => 'Status', 'labelAr' => 'الحالة', 'type' => 'enum', 'value' => 'active', 'options' => ['active' => ['label' => 'Active', 'labelAr' => 'نشط', 'variant' => 'success']]],
        ['id' => 'vip', 'label' => 'VIP', 'labelAr' => 'مميز', 'type' => 'boolean', 'value' => true],
        ['id' => 'email', 'label' => 'Email', 'type' => 'email', 'value' => 'hello@acme.test', 'copyable' => true],
    ]"
/>
```

### HTML + Alpine

```html
<div data-slot="infolist" role="group"  class="flex flex-col gap-8">
                    <section  class="flex flex-col gap-4">
                        <dl class="grid grid-cols-1 gap-x-8 gap-y-4 sm:grid-cols-2">
                                                                                                <div data-slot="infolist-item" class="min-w-0 flex flex-col gap-1">
                        <dt class="text-caption text-muted-foreground">
                            <bdi dir="auto">Name</bdi>
                        </dt>
                        <dd class="m-0 flex min-w-0 items-center gap-1.5 text-body text-foreground">
                                                            <bdi dir="auto" class="whitespace-pre-line">Acme Trading</bdi>
                                                                                </dd>
                                            </div>
                                                                                                <div data-slot="infolist-item" class="min-w-0 flex flex-col gap-1">
                        <dt class="text-caption text-muted-foreground">
                            <bdi dir="auto">Status</bdi>
                        </dt>
                        <dd class="m-0 flex min-w-0 items-center gap-1.5 text-body text-foreground">
                                                            <span data-slot="badge"     class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-nq-success/40 bg-nq-success-soft text-nq-success-text"><bdi dir="auto">Active</bdi></span>
                                                                                </dd>
                                            </div>
                                                                                                <div data-slot="infolist-item" class="min-w-0 flex flex-col gap-1">
                        <dt class="text-caption text-muted-foreground">
                            <bdi dir="auto">VIP</bdi>
                        </dt>
                        <dd class="m-0 flex min-w-0 items-center gap-1.5 text-body text-foreground">
                                                                                                <span data-slot="badge"     class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-nq-success/40 bg-nq-success-soft text-nq-success-text"><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="M20 6 9 17l-5-5"/>
</svg>Yes</span>
                                                                                                                </dd>
                                            </div>
                                                                                                <div data-slot="infolist-item" class="min-w-0 flex flex-col gap-1">
                        <dt class="text-caption text-muted-foreground">
                            <bdi dir="auto">Email</bdi>
                        </dt>
                        <dd class="m-0 flex min-w-0 items-center gap-1.5 text-body text-foreground">
                                                            <a href="mailto:hello@acme.test" dir="ltr" class="break-all text-foreground underline underline-offset-2">hello@acme.test</a>
                                                                                        <span class="contents" x-data="nqCopyButton('hello@acme.test', 1500)">
    <button data-slot="copy-button"
     type="button"                         aria-label="Copy" x-on:click="copy()" x-bind:data-copied="state === &#039;copied&#039; ? &#039;&#039; : null" 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]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0 data-copied:text-nq-success-text">
        <svg aria-hidden="true" x-show="state !== 'copied'" 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">
  <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
  <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>
</svg>        <svg aria-hidden="true" x-show="state === 'copied'" style="display: none" 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="M20 6 9 17l-5-5"/>
</svg></button>
    <span data-slot="copy-button-status" role="status" aria-live="polite" class="sr-only"
        data-copied-label="Copied to clipboard" data-failed-label="Could not copy"
        x-text="state === 'copied' ? $el.dataset.copiedLabel : state === 'failed' ? $el.dataset.failedLabel : ''"></span>
</span>
                                                    </dd>
                                            </div>
                            </dl>
        </section>
    </div>
```
