# useActiveIdRegistry

[Back to Composables README](https://github.com/NantHealth/featherk/blob/integration/packages/composables/README.md)

Tracks a single active id across a list of rendered elements (grid rows, tabs, action buttons, etc.) while also resolving that id back to its mounted DOM element.

This helper is for shared-instance patterns where one popup/menu instance is reused across many triggers, but only a single item should be active/open at a time.

## Why use it

When a popup or menu instance is shared across a grid or list, a simple boolean per item is not enough to coordinate the active target. `useActiveIdRegistry` keeps two things in sync:

- the active id for the list
- the mounted element for that active id

This lets consumers derive both `isOpen` and `triggerRef` from the same registry, rather than re-implementing one-off bookkeeping in each view.

## Quick Start

1. Create a registry instance at the shared list boundary so one active id drives the whole set of triggers.
2. Register each mounted element by id as it appears or re-renders, including Kendo/Vue component refs via `$el`.
3. Bind the registry's `isActive`/`activeElement` to the shared popup/menu instance and activate the item that should open.
4. Deactivate when the item closes so the previously active trigger is demoted and the next item can become active.

```ts
// Step 1: one registry manages the list-wide active id
const registry = useActiveIdRegistry<number>();

// Step 2: register each element as it mounts or re-renders
registry.register(1, rowElement); // Step 2
registry.register(2, buttonElement); // Step 2

// Step 3: connect the registry to a shared popup/menu instance
const isOpen = registry.isActive;
const triggerRef = registry.activeElement;

// Step 4: activate/deactivate when the current item opens or closes
registry.activate(2);

if (registry.isIdActive(2)) {
  // active row/button is selected
}

registry.deactivate();
```

## Basic Usage

```ts
const rowRegistry = useActiveIdRegistry<number>();

const rowMenu = usePopupMenu({
  isOpen: rowRegistry.isActive,
  triggerRef: rowRegistry.activeElement,
  menuRef: rowMenuRef,
  triggerMode: "row",
  requestShow: () => {
    // parent-owned open state is handled by registry activation
  },
  requestHide: () => rowRegistry.deactivate(),
});

const toggleRowMenu = (id: number) => {
  if (rowRegistry.isIdActive(id)) {
    rowRegistry.deactivate();
    return;
  }

  rowRegistry.activate(id);
};
```

This pattern is designed for one shared popup/menu instance across many rendered items. The active id stays in sync with the mounted DOM element, so the popup opens against the correct trigger without a per-item boolean for every row.

## API

```ts
const registry = useActiveIdRegistry<number>();

registry.register(1, rowElement);
registry.register(2, buttonElement);

registry.activate(2);

const isOpen = registry.isActive;
const triggerRef = registry.activeElement;

if (registry.isIdActive(2)) {
  // active row/button is selected
}

registry.deactivate();
```

## Return shape

- `activeId`: readonly current id or `null`
- `isActive`: computed `true` when an id is active
- `activeElement`: computed DOM element for the active id
- `register(id, el)`: stores or removes the element for a given id
- `resolve(id)`: returns the registered DOM element for `id`
- `activate(id)`: sets the active id
- `deactivate()`: clears the active id
- `isIdActive(id)`: checks whether a given id is the current active id

## Shared-instance popup usage

```ts
const rowRegistry = useActiveIdRegistry<number>();

const rowMenu = usePopupMenu({
  isOpen: rowRegistry.isActive,
  triggerRef: rowRegistry.activeElement,
  menuRef: rowMenuRef,
  triggerMode: "row",
  requestShow: () => {
    // parent-owned open state is handled by activation logic
  },
  requestHide: () => rowRegistry.deactivate(),
});

const toggleRowMenu = (id: number) => {
  if (rowRegistry.isIdActive(id)) {
    rowRegistry.deactivate();
    return;
  }

  rowRegistry.activate(id);
};
```

## Notes

- Accepts both raw DOM elements and Vue/Kendo component refs exposing `$el`.
- Works well with virtualized or keyed re-renders because the registry re-resolves the current active element when the underlying DOM node changes.
- This helper is intentionally generic; it does not own popup behavior or ARIA attributes itself.
