Summary
The exported composable buttons (CodeBlockCopyButton) accept onCopy/onError callbacks, but the controls streamdown renders BY DEFAULT (via controls={{code:{copy:true}}} or the default-on config) don't expose any way to receive those events.
Consequences for hosts using the default controls:
- Silent error path: if
navigator.clipboard is unavailable (permissions policy, non-secure context) the click is a silent no-op — the host can't surface an inline error because it never learns the copy failed.
- No success hook: hosts can't attach analytics or an accessible status announcement (see the companion a11y issue) without abandoning the default controls entirely and re-owning the whole
components.code composition — which re-couples them to CodeBlock internals on every upgrade.
Suggested fix
Accept optional onCopy/onError (top-level props or a controls config extension, e.g. controls={{code:{copy:{onCopy, onError}}}}) and thread them to the internally-rendered buttons.
Summary
The exported composable buttons (
CodeBlockCopyButton) acceptonCopy/onErrorcallbacks, but the controls streamdown renders BY DEFAULT (viacontrols={{code:{copy:true}}}or the default-on config) don't expose any way to receive those events.Consequences for hosts using the default controls:
navigator.clipboardis unavailable (permissions policy, non-secure context) the click is a silent no-op — the host can't surface an inline error because it never learns the copy failed.components.codecomposition — which re-couples them to CodeBlock internals on every upgrade.Suggested fix
Accept optional
onCopy/onError(top-level props or acontrolsconfig extension, e.g.controls={{code:{copy:{onCopy, onError}}}}) and thread them to the internally-rendered buttons.