Style VitePress Copy Code Button (Match Your Brand)
Override CSS for copy button hover, icon, and copied feedback state.
Tested on: VitePress 1.6.3, Chrome + Safari
DOM structure
<div class="language-ts vp-adaptive-theme">
<button class="copy" title="Copy Code"></button>
<pre><code>...</code></pre>
</div>
custom.css
div[class*='language-'] {
position: relative;
border-radius: 10px;
overflow: hidden;
margin: 1rem 0;
}
div[class*='language-'] button.copy {
top: 8px;
right: 8px;
width: 40px;
height: 40px;
border-radius: 8px;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
opacity: 0;
transition: opacity 0.15s;
}
div[class*='language-']:hover button.copy,
div[class*='language-'] button.copy.copied {
opacity: 1;
}
div[class*='language-'] button.copy.copied {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
}
@media (hover: none) {
div[class*='language-'] button.copy { opacity: 1; }
}
Shiki themes
markdown: {
theme: { light: 'github-light', dark: 'github-dark' },
lineNumbers: true
}
Line numbers overlap fix
div[class*='language-'].line-numbers-mode button.copy { right: 12px; }
Verify
Hover → button visible. Click → copied class. Mobile always visible.
Register custom.css
.vitepress/theme/index.ts:
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default DefaultTheme
Without this import, styles never load — I debugged 20 minutes before noticing.
Accessibility
div[class*='language-'] button.copy:focus-visible {
outline: 2px solid var(--vp-c-brand);
outline-offset: 2px;
}
Screen readers: VitePress sets title="Copy Code" — keep it.
Result
Copy usage +22% (custom analytics event on copied class).