From 63a1b222afd4b373c89cef377e502cd3047e365b Mon Sep 17 00:00:00 2001 From: Isakdl Date: Tue, 6 Oct 2026 17:58:14 +0200 Subject: [PATCH] feat: Tag copy buttons with data attributes for PostHog autocapture Code block copy buttons get data-attr="copy-code" plus data-block-title and data-language. The Copy as Markdown button gets data-attr="copy-page-markdown" plus data-docs-instance and data-docs-version. PostHog autocapture records these on every click, so copies can be filtered per block and per page without custom events. Co-Authored-By: Claude Opus 5.5 --- src/components/CopyPageButton/index.js | 9 ++++++--- src/theme/CodeBlock/Buttons/CopyButton/index.js | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/components/CopyPageButton/index.js b/src/components/CopyPageButton/index.js index cfb1b2bc..e0bd26cb 100644 --- a/src/components/CopyPageButton/index.js +++ b/src/components/CopyPageButton/index.js @@ -126,6 +126,7 @@ function reportCopyEvent(params) { export default function CopyPageButton({permalink, docsVersion}) { const [state, setState] = useState('idle'); + const isCloud = permalink === '/cloud' || permalink.startsWith('/cloud/'); const resetTimer = useRef(undefined); const mounted = useRef(true); useEffect(() => { @@ -143,7 +144,6 @@ export default function CopyPageButton({permalink, docsVersion}) { window.clearTimeout(resetTimer.current); setState('loading'); const markdownPath = mdPath(permalink); - const isCloud = permalink === '/cloud' || permalink.startsWith('/cloud/'); const finish = (ok, error) => { if (error) { // Surface the cause (missing .md, clipboard denial) so a "Copy @@ -166,7 +166,7 @@ export default function CopyPageButton({permalink, docsVersion}) { () => finish(true), (error) => finish(false, error), ); - }, [state, permalink, docsVersion]); + }, [state, permalink, docsVersion, isCloud]); // aria-busy + click guard instead of `disabled`, which would drop keyboard // focus; the live region sits outside the button so screen readers still @@ -180,7 +180,10 @@ export default function CopyPageButton({permalink, docsVersion}) { })} onClick={handleClick} aria-busy={state === 'loading'} - title={title()}> + title={title()} + data-attr="copy-page-markdown" + data-docs-instance={isCloud ? 'cloud' : 'framework'} + data-docs-version={docsVersion}> diff --git a/src/theme/CodeBlock/Buttons/CopyButton/index.js b/src/theme/CodeBlock/Buttons/CopyButton/index.js index 2a355a2c..7b54bc9d 100644 --- a/src/theme/CodeBlock/Buttons/CopyButton/index.js +++ b/src/theme/CodeBlock/Buttons/CopyButton/index.js @@ -2,7 +2,9 @@ * Swizzled from @docusaurus/theme-classic to strip leading shell prompts * (`$ `) from text written to the clipboard. The prompt remains visible * in the rendered code block, but the copied text is the runnable command. - * Also reports each copy to Google Analytics as a `copy_code_block` event. + * Also reports each copy to Google Analytics as a `copy_code_block` event, + * and tags the button with `data-*` attributes that PostHog autocapture + * records on every click. */ import React, {useCallback, useState, useRef, useEffect} from 'react'; import clsx from 'clsx'; @@ -93,15 +95,23 @@ function useCopyButton() { }); }, [code, language, blockTitle]); useEffect(() => () => window.clearTimeout(copyTimeout.current), []); - return {copyCode, isCopied}; + return { + copyCode, + isCopied, + language, + blockTitle: typeof blockTitle === 'string' ? blockTitle : undefined, + }; } export default function CopyButton({className}) { - const {copyCode, isCopied} = useCopyButton(); + const {copyCode, isCopied, language, blockTitle} = useCopyButton(); return (