Getting StartedInstall and bootstrap headless foundations 4
LayoutHeadless structural primitives for expandable and container patterns 6
OverlayHeadless modal and floating layer behavior 3
FeedbackHeadless notification and status communication patterns 5
FormHeadless input and selection contracts 17
UtilityReusable action, identity, and clipboard behavior 6
NavigationHeadless trails, trees, menus, and command surfaces 7

Styling contract

Headless copy triggers only expose host-level behavior. Shape, colors, iconography, and live announcement presentation stay fully owner-controlled.

Host state hooks

HookWhen it appearsUse it for
data-copy-disabledWhenever the primitive is disabled, including non-button hosts.Visual disabled states that work for both native and custom hosts.
aria-disabled="true"Only on non-button hosts.Styling custom triggers that still need disabled semantics.
disabledOnly on native button hosts.Native button disabled states.

Host selectors

css
[data-copy-disabled]
[aria-disabled="true"]
[disabled]

CSS starter

Start with a normal button treatment, then add your own focus ring, icon rhythm, and copied state visuals around the primitive events.

copy-trigger.css

css
.docs-copy-trigger {
  align-items: center;
  appearance: none;
  border: 1px solid var(--tng-semantic-border-strong);
  border-radius: 0.65rem;
  display: inline-flex;
  font: inherit;
  font-weight: 600;
  gap: 0.45rem;
  min-height: 2.5rem;
  padding: 0 0.95rem;
}

.docs-copy-trigger:focus-visible {
  box-shadow: 0 0 0 3px var(--tng-semantic-focus-ring);
  outline: none;
}

.docs-copy-trigger[data-copy-disabled],
.docs-copy-trigger[aria-disabled="true"],
.docs-copy-trigger:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

Announcement guidance

The primitive does not render its own live region. Use tngCopyAnnounced when you want to mirror success or error copy feedback into your own visually hidden status node.

Owner-managed live region

html
<button
  type="button"
  tngCopy
  class="docs-copy-trigger"
  [tngCopyText]="payload"
  tngCopyButtonAnnounce="true"
  (tngCopyAnnounced)="announcement.set($event)"
>
  Copy payload
</button>

<p class="sr-only" aria-live="polite">{{ announcement() }}</p>