# Port picker
> Form-associated port field that knows the host: it shows neighbouring ports, rejects taken ones and suggests the nearest free ports.
- Element: `<sv-port-picker>`
- React: `import { SvPortPicker } from "@/components/lumesec/sv-port-picker"`
- Collection: Service Map (https://elements.lumesec.ai/components/service-map)
- Registry item: https://elements.lumesec.ai/r/sv-port-picker.json
- Page: https://elements.lumesec.ai/components/service-map/port-picker



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

```html
<sv-port-picker name="port" host="app-01" value="8080"></sv-port-picker>
```

## 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-port-picker
```

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-port-picker.json
```

## Usage

React:

```tsx
import { SvPortPicker } from "@/components/lumesec/sv-port-picker";

export function Example() {
  return (
    <SvPortPicker name="port" host="app-01" value="8080" />
  );
}
```

HTML:

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

<sv-port-picker name="port" host="app-01" value="8080"></sv-port-picker>
```

## Behaviour

A form field that knows the host. It shows the neighbouring ports, rejects taken ones and offers the nearest free port.

## API reference

### Attributes

| Attribute | React prop | Type     | Default  | Description                                                                                                                                   |
| --------- | ---------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`    | `name`     | `string` | —        | Field name used when the form is submitted.                                                                                                   |
| `host`    | `host`     | `string` | `app-01` | Host id that preselects the host menu, for example `db-01`. An id that is not in the menu falls back to `app-01`. Read once on first connect. |
| `value`   | `value`    | `string` | `8080`   | Initial port. Read once on first connect; use the `value` property afterwards.                                                                |

### Events

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

| Event   | React prop | Detail                                          | Description                                                                                                                                                                                                    |
| ------- | ---------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `input` | `onInput`  | `{ host: string, port: number, free: boolean }` | Fires on user changes: typing, arrow keys, choosing a host, or clicking a ruler port or suggestion. `port` is `NaN` when the field is not a number; `free` is true only for a port in range that is not taken. |

### Properties

| Property           | Type                      | Description                                                                                        |
| ------------------ | ------------------------- | -------------------------------------------------------------------------------------------------- |
| `value`            | `string`                  | Port text in the field. Setting it re-validates and updates the form value without firing `input`. |
| `form` (read-only) | `HTMLFormElement \| null` | The form the element is associated with.                                                           |
| `name` (read-only) | `string \| null`          | Mirrors the `name` attribute.                                                                      |

## Keyboard

| Keys                | Action                                                           |
| ------------------- | ---------------------------------------------------------------- |
| ArrowUp / ArrowDown | In the port field: next or previous port, clamped to 1 to 65535. |

## Accessibility

* The port field has a visible label and is described by the status line (`aria-describedby`), which is a polite live region.
* A taken or out-of-range port sets `aria-invalid="true"` on the field; the element's validity is anchored to it.
* The neighbouring ports are a `role="group"` labelled Neighbouring ports; each button's `aria-label` says whether the port is free or which service uses it.
* Form-associated through `ElementInternals`. Submits `name` with the value `<host>:<port>`, for example `app-01:8080`, or an empty value when the port is outside 1 to 65535. Validity: `rangeOverflow` (Port out of range) for values outside 1 to 65535 or not a number, `customError` (Port N is in use) for a taken port, valid otherwise.
* Reduced motion: no animation; reduced motion has no effect on this element.

## 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`, `--destructive`, `--foreground`, `--lumesec`, `--lumesec-success` and `--muted-foreground`.

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

## Notes

* Port occupancy comes from the shared demo infrastructure `INFRA`; `host="app-01"` selects the record.
* The inner field's native `input` event stays inside the shadow root, so `input` listeners on the element receive only the element's own event, with `host`, `port` and `free` in `detail`.
* The ruler shows nine ports centred on the value, seven under 360 px. For a taken port, up to three free ports above it are suggested.


