Styling contract
Host state hooks
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>