# Web Component Composition

React HUMAIN components often use compound slots such as `Card.Content`, `AppShellCard.Header`, and `Dialog.Footer`. Web Components may not expose every compound slot as a tag. Use only exported tags and manifest-backed attributes.

## Composition Rules

| WC tag | React pattern | Difference | Required WC pattern |
| --- | --- | --- | --- |
| `hf-app-shell-card` | `AppShellCard inside AppShell.Panel` | Use this component for dashboard and app panels that need shell chrome. | Place hf-page-header first, then panel content. Use body-padding="none" for edge-to-edge tables or charts; omit body-padding for padded content. |
| `hf-card` | `Card.Content` | The Web Component root maps to the React Card root, not to Card.Content. | Wrap body content in a data-hf-slot="card-content" element when it needs tokenized padding. |
| `hf-data-table` | `DataTable in an AppShellCard body` | Data tables should live in app panels, not inside nested raw cards. | Use hf-app-shell-card with body-padding="none" when the table should run edge to edge. |
| `hf-field` | `Field with labeled form controls` | The WC field root exposes layout, state, disabled, and required attributes only. | Use visible text inside hf-field and supported aria attributes on the nested control. |
| `hf-radio-group` | `RadioGroup or option-set controls` | Option groups use manifest-backed JSON data attributes. | Use items JSON plus supported value/default-value/name attributes. |
| `hf-switch` | `Switch` | The WC switch exposes label, description, and controlled or uncontrolled checked state. | Use label and description, then set checked or default-checked and listen for checked-change when state is interactive. |

## Card Content

React:

```tsx
<Card>
  <Card.Header>
    <Card.Title>Plan</Card.Title>
  </Card.Header>
  <Card.Content>Body</Card.Content>
</Card>
```

WC-safe structure:

```html
<hf-card>
  <div data-hf-slot="card-content" class="hf-card-content">
    <h2>Plan</h2>
    <p>Body</p>
  </div>
</hf-card>
```

Required CSS until the WC package exposes first-class content slots:

```css
.hf-card-content {
  display: grid;
  gap: var(--spacing-3);
  padding: var(--spacing-6);
}
```

Do not place heading or paragraph body content directly under `hf-card`.

## App Panels

Use `hf-app-shell-card` for authenticated product panels.

```html
<hf-app-shell-card>
  <hf-page-header title="Revenue operations" supporting-text="Pipeline and workload"></hf-page-header>
  <hf-data-table columns="[]" data="[]"></hf-data-table>
</hf-app-shell-card>
```

The `hf-app-shell-card` body uses standard padding by default. Add `body-padding="none"` when the panel needs edge-to-edge table, chart, or media content.

## Forms

Use supported form elements and visible label text.

```html
<hf-card>
  <div data-hf-slot="card-content" class="hf-card-content">
    <hf-page-header title="Invite user"></hf-page-header>
    <hf-field required>
      <span>Email</span>
      <hf-input aria-label="Email"></hf-input>
    </hf-field>
    <hf-radio-group
      name="role"
      items='[{"label":"Admin","value":"admin"},{"label":"Viewer","value":"viewer"}]'
    ></hf-radio-group>
    <hf-button>Send invite</hf-button>
  </div>
</hf-card>
```

Do not invent `label` on `hf-field` or `options` on `hf-radio-group`. For switch state, use `checked` or `default-checked` and listen for `checked-change`.
