# Table

Responsive native table primitives for invoices, product lists, row actions, and compact data summaries.

Use Table when information has real row and column relationships. The Angular primitive keeps shadcn's composition model while preserving semantic `<table>`, `<thead>`, `<tbody>`, `<tfoot>`, `<tr>`, `<th>`, `<td>`, and `<caption>` elements.

shadcn's `data-table` guide maps to this entrypoint rather than a separate Angular package surface. Compose Table with the local button, checkbox, input, badge, and dropdown-menu primitives when you need sorting, filtering, row selection, column visibility, row actions, or pagination.

## Import

```ts
import {
  TableBodyComponent,
  TableCaptionComponent,
  TableCellComponent,
  TableComponent,
  TableFooterComponent,
  TableHeadComponent,
  TableHeaderComponent,
  TableRowComponent,
} from '@edsis/component/table';
```

Row action menus can compose with the local button and dropdown-menu primitives.

```ts
import { ButtonComponent } from '@edsis/component/button';
import {
  MenuContentDirective,
  MenuItemComponent,
  MenuSeparatorComponent,
  MenuSurfaceComponent,
  MenuTriggerDirective,
} from '@edsis/component/dropdown-menu';
```

## Composition

Apply the attribute-selector parts to the matching semantic table tags.

```text
Table
|-- caption[TableCaption]
|-- thead[TableHeader]
|   `-- tr[TableRow]
|       |-- th[TableHead]
|       |-- th[TableHead]
|       |-- th[TableHead]
|       `-- th[TableHead]
|-- tbody[TableBody]
|   `-- tr[TableRow]
|       |-- td[TableCell]
|       |-- td[TableCell]
|       |-- td[TableCell]
|       `-- td[TableCell]
`-- tfoot[TableFooter]
```

## Usage

Use `Table` as the responsive wrapper. Bind rows with Angular control flow and stable tracking.

```html
<table>
  <caption TableCaption>
    A list of your recent invoices.
  </caption>
  <thead TableHeader>
    <tr TableRow>
      <th TableHead class="w-25">Invoice</th>
      <th TableHead>Status</th>
      <th TableHead>Method</th>
      <th TableHead class="text-right">Amount</th>
    </tr>
  </thead>
  <tbody TableBody>
    @for (invoice of invoices; track invoice.invoice) {
    <tr TableRow>
      <td TableCell class="font-medium">{{ invoice.invoice }}</td>
      <td TableCell>{{ invoice.status }}</td>
      <td TableCell>{{ invoice.method }}</td>
      <td TableCell class="text-right">{{ invoice.amount }}</td>
    </tr>
    }
  </tbody>
</table>
```

## Common patterns

### Footer totals

Use `tfoot[TableFooter]` for totals and summaries. `colspan` stays on the native `td`.

```html
<table>
  <caption TableCaption>
    A list of your recent invoices.
  </caption>
  <thead TableHeader>
    ...
  </thead>
  <tbody TableBody>
    ...
  </tbody>
  <tfoot TableFooter>
    <tr TableRow>
      <td TableCell colspan="3">Total</td>
      <td TableCell class="text-right">$2,500.00</td>
    </tr>
  </tfoot>
</table>
```

### Row actions

Compose action menus with `Button`, `MenuTrigger`, and the dropdown-menu surface.

```html
<ng-template MenuContent #productActionsMenu="MenuContent">
  <MenuSurface class="w-36">
    <button MenuItem>Edit</button>
    <button MenuItem>Duplicate</button>
    <MenuSeparator />
    <button MenuItem variant="destructive">Delete</button>
  </MenuSurface>
</ng-template>

<table>
  <thead TableHeader>
    <tr TableRow>
      <th TableHead>Product</th>
      <th TableHead>Price</th>
      <th TableHead class="text-right">Actions</th>
    </tr>
  </thead>
  <tbody TableBody>
    @for (product of products; track product.name) {
    <tr TableRow>
      <td TableCell class="font-medium">{{ product.name }}</td>
      <td TableCell>{{ product.price }}</td>
      <td TableCell class="text-right">
        <button
          Button
          type="button"
          variant="ghost"
          size="icon-sm"
          [attr.aria-label]="'Open actions for ' + product.name"
          [MenuTrigger]="productActionsMenu"
        >
          <span aria-hidden="true">...</span>
        </button>
      </td>
    </tr>
    }
  </tbody>
</table>
```

### Data table guide mapping

The upstream shadcn `data-table` page is a composition guide, not a standalone primitive. In this Angular library the same guidance starts with `@edsis/component/table` and layers behavior around it.

```ts
import { BadgeComponent } from '@edsis/component/badge';
import { ButtonComponent } from '@edsis/component/button';
import { CheckboxComponent } from '@edsis/component/checkbox';
import {
  MenuCheckboxItemComponent,
  MenuContentDirective,
  MenuGroupComponent,
  MenuItemComponent,
  MenuLabelComponent,
  MenuSeparatorComponent,
  MenuSurfaceComponent,
  MenuTriggerDirective,
} from '@edsis/component/dropdown-menu';
import { InputComponent } from '@edsis/component/input';
```

Keep Table as the markup layer and put behavior in Angular signals, services, or a table state library. A small explicit pipeline is usually easier to maintain than a generic catch-all data-table wrapper.

```ts
readonly filterText = signal('');
readonly sortState = signal<{ column: 'status' | 'email' | 'amount'; direction: 'asc' | 'desc' } | null>(null);
readonly selectedIds = signal<ReadonlySet<string>>(new Set());

readonly filteredRows = computed(() => {
  const query = filterText().trim().toLowerCase();
  return query ? rows.filter((row) => row.email.toLowerCase().includes(query)) : rows;
});

readonly sortedRows = computed(() => sortRows(filteredRows(), sortState()));
readonly pageRows = computed(() => paginateRows(sortedRows(), currentPage(), pageSize));
```

Selected rows can use the shadcn-compatible `data-state="selected"` hook so row styling stays synchronized with the checkbox state.

```html
<table>
  <thead TableHeader>
    ...
  </thead>
  <tbody TableBody>
    @for (row of filteredRows(); track row.id) {
    <tr TableRow [attr.data-state]="selectedIds().has(row.id) ? 'selected' : null">
      <td TableCell>{{ row.title }}</td>
      <td TableCell>{{ row.status }}</td>
      <td TableCell class="text-right">{{ row.amount }}</td>
    </tr>
    }
  </tbody>
</table>
```

### RTL

Set direction on a wrapper or directly on `Table`. Keep alignment explicit for amount and numeric columns.

```html
<div dir="rtl" lang="ar" class="text-right">
  <table>
    <caption TableCaption>
      قائمة بفواتيرك الأخيرة.
    </caption>
    <thead TableHeader>
      <tr TableRow>
        <th TableHead class="w-25 text-right">الفاتورة</th>
        <th TableHead class="text-right">الحالة</th>
        <th TableHead class="text-right">الطريقة</th>
        <th TableHead class="text-right">المبلغ</th>
      </tr>
    </thead>
    <tbody TableBody>
      ...
    </tbody>
  </table>
</div>
```

## API reference

### `TableComponent`

| Input   | Type     | Default | Description                                       |
| ------- | -------- | ------- | ------------------------------------------------- |
| `class` | `string` | `''`    | Classes applied to the rendered native `<table>`. |

### Attribute parts

| Part                    | Selector                | Input   | Notes                                                   |
| ----------------------- | ----------------------- | ------- | ------------------------------------------------------- |
| `TableCaptionComponent` | `caption[TableCaption]` | `class` | Muted caption below the table.                          |
| `TableHeaderComponent`  | `thead[TableHeader]`    | `class` | Header section with row dividers.                       |
| `TableBodyComponent`    | `tbody[TableBody]`      | `class` | Body section that removes the final row border.         |
| `TableFooterComponent`  | `tfoot[TableFooter]`    | `class` | Footer section with muted background and top divider.   |
| `TableRowComponent`     | `tr[TableRow]`          | `class` | Row hover state and `data-state="selected"` support.    |
| `TableHeadComponent`    | `th[TableHead]`         | `class` | Header cell with muted foreground and nowrap text.      |
| `TableCellComponent`    | `td[TableCell]`         | `class` | Body or footer cell with compact padding and alignment. |

## Styling and theming

The root host is `relative block w-full overflow-x-auto`; the rendered table is `w-full caption-bottom text-sm`.

Dividers use the shared `border-border` token, row hover uses `hover:bg-muted/50`, footer uses `bg-muted/50`, and selected rows respond to `data-state="selected"` with `bg-muted`.

Pass utility classes to individual parts for column width, alignment, density, responsive visibility, and typography.

## Accessibility

- Use a `<caption TableCaption>` when the table conveys meaningful data.
- Keep column headers in native `<th TableHead>` cells so screen readers can announce header relationships.
- Use `scope`, `colspan`, `rowspan`, and `aria-sort` on native cells when your data model needs them.
- Do not use Table for non-tabular layout. Use CSS grid or flex layouts for purely visual alignment.

## Keyboard interactions

Static tables do not add custom keyboard behavior. Focusable controls inside cells, such as action menu buttons, keep their own native or primitive-provided keyboard behavior.

When composing a row menu, the trigger uses native button activation and the local menu handles Arrow Up, Arrow Down, Home, End, Tab dismissal, and typeahead.

## Angular notes

- All table parts are standalone components and can be imported directly.
- The root `Table` wraps projected content in a native `<table>`, so child parts should be direct table descendants in normal HTML order.
- Prefer Angular `@for` with a stable `track` expression for row rendering.
- Keep sorting, filtering, pagination, and selection state outside the primitive; Table is intentionally presentational.
- Attribute-selector primitives must be applied to their semantic tag, for example `th[TableHead]` and `td[TableCell]`.

## Source parity

This Angular implementation follows the shadcn Table docs for preview, usage, composition, footer, actions, data-table guidance, and RTL. React component names map to Angular selectors, React `className` maps to `class`, and row action menus compose with the local Angular dropdown-menu primitives.
