# Toggle API

### Global API (`window.Toggles`)

The component exposes a global registry to interact with toggle instances programmatically.

#### `window.Toggles.getAll()`

Returns an array of all initialized `Toggle` class instances on the page.

#### `window.Toggles.findById(id)`

Returns the `Toggle` instance with the matching button ID.

#### `window.Toggles.findByTarget(targetId)`

Returns an array of `Toggle` instances that target the specified element ID.

***

### Instance API (`Toggle`)

Each toggle instance provides properties and methods for state control.

#### Properties

* `id`: The unique ID of the toggle (generated if not present on the button).
* `button`: The HTML button element.
* `target`: The HTML target element (resolved at runtime).
* `isEnabled`: Boolean indicating if the toggle is currently active (supports getter and setter).
* `config`: The parsed configuration object (read-only via `getConfig()`).

#### Methods

* `enable()`: Activates the toggle.
* `disable()`: Deactivates the toggle.
* `toggle()`: Flips the current state.
* `setEnabled(boolean)`: Explicitly sets the state.
* `updateLabelWidth()`: Force recalculation of label widths (if in `alternate` mode).
* `on(eventName, handler)`: Adds an event listener to the **target** element.
* `off(eventName, handler)`: Removes an event listener from the **target** element.
* `getConfig()`: Returns a copy of the parsed configuration from data attributes.

***

### Events

Events are dispatched from the **target element**. They bubble up and are not cancelable.

| Event Name       | Detail                       | Description                           |
| ---------------- | ---------------------------- | ------------------------------------- |
| `toggle:enable`  | `{ id, isEnabled: true }`    | Fired when the toggle is activated.   |
| `toggle:disable` | `{ id, isEnabled: false }`   | Fired when the toggle is deactivated. |
| `toggle:change`  | `{ id, isEnabled: boolean }` | Fired on any state change.            |

***

### Examples

#### Programmatic Toggle Control

```javascript
// Find a toggle by its button ID
const menuToggle = window.Toggles.findById("menu-toggle");

// Open the toggle target
menuToggle.enable();

// Close the toggle target
menuToggle.disable();

// Toggle the current state
menuToggle.toggle();

// Set state explicitly
menuToggle.setEnabled(true);  // Open
menuToggle.setEnabled(false); // Close

// Check current state
if (menuToggle.isEnabled) {
  console.log("Menu is open");
}

// Get all toggle instances
const allToggles = window.Toggles.getAll();
console.log(`Found ${allToggles.length} toggles on the page`);
```

#### Finding Toggles by Target

```javascript
// Find all toggle buttons that control "mobile-menu"
const menuToggles = window.Toggles.findByTarget("mobile-menu");

console.log(`${menuToggles.length} buttons control the mobile menu`);

// Disable all of them (closes the menu)
menuToggles.forEach(toggle => toggle.disable());

// Enable via any of them (opens the menu, all stay synced)
menuToggles[0].enable();
```

#### Event Listeners for State Changes

```javascript
const menuTarget = document.getElementById("mobile-menu");

// Listen for enable (open)
menuTarget.addEventListener("toggle:enable", (e) => {
  console.log(`Toggle ${e.detail.id} opened the menu`);
  
  // Track analytics
  analytics.track("menu_opened");
});

// Listen for disable (close)
menuTarget.addEventListener("toggle:disable", (e) => {
  console.log(`Toggle ${e.detail.id} closed the menu`);
});

// Listen for any state change
menuTarget.addEventListener("toggle:change", (e) => {
  const { id, isEnabled } = e.detail;
  console.log(`Menu is now ${isEnabled ? "open" : "closed"}`);
  
  // Update UI based on state
  document.body.classList.toggle("menu-active", isEnabled);
});
```

#### Using Instance Event Methods

```javascript
const toggle = window.Toggles.findById("menu-toggle");

// Add event listener via instance method (attaches to target element)
function handleChange(e) {
  console.log(`State changed: ${e.detail.isEnabled}`);
}

toggle.on("toggle:change", handleChange);

// Later, remove the listener
toggle.off("toggle:change", handleChange);
```

#### Reading Toggle Configuration

```javascript
const toggle = window.Toggles.findById("menu-toggle");

// Get a copy of the parsed configuration
const config = toggle.getConfig();

console.log(config);
// Output:
// {
//   targetId: "mobile-menu",
//   targetToggledClass: "is-open",
//   freezeScroll: true,
//   labelMode: "alternate",
//   nextFocusId: null,
//   targetIsModal: false
// }

// Access individual config values
if (config.freezeScroll) {
  console.log("This toggle freezes scroll when active");
}
```

#### Close All Open Toggles

```javascript
// Close all active toggles on the page
function closeAllToggles() {
  window.Toggles.getAll()
    .filter(toggle => toggle.isEnabled)
    .forEach(toggle => toggle.disable());
}

// Example: Close all toggles on route change (SPA)
window.addEventListener("popstate", closeAllToggles);

// Example: Close all toggles with Escape (handled automatically, but custom logic)
document.addEventListener("keydown", (e) => {
  if (e.key === "Escape") {
    closeAllToggles();
  }
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.nickarce.com/javascript-api/toggle-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
