CngxButtonToggle
button[cngxButtonToggle]
projects/common/interactive/button-toggle/button-toggle.directive.ts
Import#
import { CngxButtonToggle } from '@cngx/common/interactive'
Description#
Button-toggle leaf. Restricted to <button> elements via the
button[cngxButtonToggle] selector so consumers cannot
accidentally apply the directive to a <div> and lose the
native button semantics (Space + Enter activation, focus ring,
disabled propagation to the form-submission engine).
Injects EITHER CNGX_BUTTON_TOGGLE_GROUP (single, radiogroup) OR
CNGX_BUTTON_MULTI_TOGGLE_GROUP (multi, toolbar) - never the
concrete group class - both with { optional: true }.
Exactly one parent must be present; the constructor throws when both or
neither resolve. The resolved parent is stored as a discriminated
union ({ mode: 'single' | 'multi'; group }) so every downstream
branch narrows without non-null assertions.
The present token determines:
- the ARIA pattern (
aria-checkedfor single,aria-selectedfor multi), bound on the host AT INJECTION TIME, - the activation contract (single:
group.value.set(...); multi:group.toggle(...)), - whether
(focus)consumes the parent's pending arrow-select flag (single only - multi follows toolbar APG, which does not auto-select on arrow nav).
Mode is static per atom instance.
There is no runtime [selectionMode] flag. Per feedback_select_family_split,
single + multi are two distinct groups reusing this leaf; the
decision is made by the consumer at template-authoring time.
Composes CngxRovingItem as a host directive with input
forwarding ('cngxRovingItemDisabled: disabled') so arrow-key
navigation in either parent group skips per-toggle-disabled leaves
automatically.
Group-disabled cascade vs roving.
Thev group-level [disabled] cascade short-circuits handleSelect /
handleKeydown / handleFocus (see toggleDisabled computed),
but does NOT propagate into CngxRovingItem.disabled.
Angular forbids re-binding a host-directive's read-only InputSignal
input from a wrapping host. As a result, a fully-disabled group
lets visual focus transit through its toggles via Arrow keys;
every selection pathway short-circuits silently.
Re-evaluation is gated on CngxRovingItem.disabled becoming a
writable surface in @cngx/common/a11y.
Disabled "why" via aria-describedby. Pillar 2 requires
disabled state to communicate a reason. The leaf exposes
[describedBy] (alias cngxDescribedBy).
A reactive input that binds to the host's aria-describedby. Consumers render the
description element themselves and pass its id; the directive does
not own a sr-only span (it is a @Directive on a native
<button> - no template to inject siblings into).
Native <button aria-describedby> semantics apply.
Metadata#
Host#
Index#
Inputs
Derived State
HostBindings
HostListeners
Inputs#
TMethods#
HostBindings#
| Binding | Expression |
|---|---|
[attr.aria-checked] | ariaChecked() |
[attr.aria-selected] | ariaSelected() |
[attr.aria-disabled] | toggleDisabled() ? "true" : null |
[attr.aria-describedby] | describedBy() |
[attr.disabled] | toggleDisabled() ? "" : null |
[class.cngx-button-toggle--checked] | toggleChecked() |
[class.cngx-button-toggle--disabled] | toggleDisabled() |
HostListeners#
| Event | Handler |
|---|---|
(focus) | focus() |
(click) | click() |
(keydown.space) | keydown.space() |
(keydown.enter) | keydown.enter() |