# Application shell
> Application shell with navigation, environment switch, search and a queue that collects planned changes from the components inside it.
- Element: `<sv-shell>`
- React: `import { SvShell } from "@/components/lumesec/sv-shell"`
- Collection: Service Map (https://elements.lumesec.ai/components/service-map)
- Registry item: https://elements.lumesec.ai/r/sv-shell.json
- Page: https://elements.lumesec.ai/components/service-map/shell



Live preview: https://elements.lumesec.ai/view/sv-shell

```html
<sv-shell>
  <svg slot="brand">…lockup…</svg>
  <sv-map slot="main" fill></sv-map>
</sv-shell>
```

## Playground

Change a prop and the component updates. Props marked live animate to the new value; the others rebuild the element.

## Installation

```bash
npx shadcn@latest add @lumesec/sv-shell
```

First time with the @lumesec registry? Register it once, or install by URL:

```bash
npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json
npx shadcn@latest add https://elements.lumesec.ai/r/sv-shell.json
```

## Usage

React:

```tsx
import { SvShell } from "@/components/lumesec/sv-shell";
import { SvMap } from "@/components/lumesec/sv-map";

export function Example() {
  return (
    <SvShell>
      <span slot="brand">Your logo</span>
      <SvMap slot="main" fill />
    </SvShell>
  );
}
```

HTML:

```html
<script type="module" src="https://elements.lumesec.ai/cdn/sv-shell.js"></script>
<script type="module" src="https://elements.lumesec.ai/cdn/sv-map.js"></script>

<sv-shell>
  <span slot="brand">Your logo</span>
  <sv-map slot="main" fill></sv-map>
</sv-shell>
```

## Behaviour

Navigation by inventory, traffic and operations, an environment switch, search and a pending-changes queue. Anything a component inside plans arrives in the queue; Apply runs it and hands the result back to the map. Under 760 px the navigation becomes a drawer.

## API reference

### Attributes

| Attribute | React prop | Type     | Default | Description                                         |
| --------- | ---------- | -------- | ------- | --------------------------------------------------- |
| `height`  | `height`   | `number` | `780`   | Shell height in pixels. Read once on first connect. |

### Events

Events bubble and cross the shadow boundary unless the description says otherwise.

| Event         | React prop      | Detail              | Description                                                                                                                                                                                                                                    |
| ------------- | --------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `navigate`    | `onNavigate`    | `{ view: string }`  | Fires when a navigation item is clicked. `view` is `overview`, `map`, `hosts`, `services`, `ports`, `proxy`, `certs`, `changes` or `settings`. The shell marks the item current and updates the breadcrumb; swapping the content is up to you. |
| `environment` | `onEnvironment` | `{ env: string }`   | Fires when an environment button is clicked. `env` is `Production` or `Staging`.                                                                                                                                                               |
| `search`      | `onSearch`      | `{ query: string }` | Fires when Enter is pressed in the search field.                                                                                                                                                                                               |
| `apply`       | `onApply`       | `{ count: number }` | Fires when Apply finishes, with the number of changes applied.                                                                                                                                                                                 |

### Methods

Call them on the element, for example through a React ref.

| Method    | Description                                                                                                                                                                           |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apply()` | Applies the queued changes: runs the progress bar, empties the queue, calls `applyPlanned()` on every descendant that has it and fires `apply`. Does nothing when the queue is empty. |

### Slots

| Slot        | Description                                                                                             |
| ----------- | ------------------------------------------------------------------------------------------------------- |
| `brand`     | Logo at the top of the sidebar, shown 22 px high.                                                       |
| `toolbar`   | Content of the bar under the header. Defaults to a sentence about planned changes. Hidden under 760 px. |
| `main`      | Main content, for example `<sv-map slot="main" fill>`.                                                  |
| `(default)` | Unslotted children are also placed in the content area.                                                 |

## Keyboard

| Keys  | Action                                                                                                                     |
| ----- | -------------------------------------------------------------------------------------------------------------------------- |
| /     | Focus the search field. Ignored while focus is in an input, textarea or select, or when the shell is outside the viewport. |
| Enter | In the search field: fire `search`.                                                                                        |

## Accessibility

* The sidebar is an `aside` labelled Main navigation; the current item has `aria-current="page"`.
* The environment switch is a `role="group"` labelled Environment with `aria-pressed` buttons.
* The search input has an `aria-label`. The drawer button is labelled Open navigation and does not expose `aria-expanded`.
* Pending changes opens a `role="dialog"` popover and has `aria-haspopup="dialog"`. Apply is disabled while the queue is empty.
* A polite live region announces how many changes were applied. The progress bar is `aria-hidden`.
* Reduced motion: apply completes after 30 ms instead of about 1.5 s, without the progress animation or pixel burst; the counter changes without rolling and the drawer and sync pulse do not animate.

## Theming

The element reads your shadcn theme tokens through its shadow root, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming).

This component reads `--background`, `--border`, `--card`, `--foreground`, `--lumesec`, `--lumesec-success`, `--muted` and `--muted-foreground`.

To restyle only LumeSec elements, set the matching `--ui-*` overrides: `--ui-accent`, `--ui-border`, `--ui-fg`, `--ui-fg2`, `--ui-mono`, `--ui-muted`, `--ui-ok`, `--ui-page`, `--ui-raised` and `--ui-surface`.

## Notes

* Any bubbling `change` event from a descendant whose `detail` has an `action` is added to the pending queue and listed in the popover with a time stamp, for example `add-service`, `migrate` or `renew-cert`. Entries are not deduplicated.
* The navigation counts (9 hosts, 19 services, 22 ports, 6 routes, 5 certificates) and the agent sync label are fixed demo text.
* Container query: under 760 px the navigation becomes a drawer behind a menu button and the search field is hidden.
* A pointer press outside the pending-changes area closes the popover.


