Code Snippet Tabs — Free HTML CSS JS Install Snippet

Code Snippet Tabs · Layouts · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Sliding ink underline
One underline element transitions translateX and width between tabs by measuring offsetLeft/offsetWidth from the DOM.
Width-aware alignment
The ink fits each tab's real label width and re-aligns on window resize, so different-length labels always look right.
Copy the shown command
Copy always reads the active tab's command from the COMMANDS array, so you get exactly what is displayed.
Clipboard with fallback
Async Clipboard API plus a hidden-textarea execCommand fallback for insecure contexts, with a CSS icon swap to a check.
Safe text insertion
Commands are set via textContent, so special characters render literally with no HTML parsing.
Keyboard tablist
role=tab/tablist with aria-selected and Arrow Left/Right navigation plus wrap-around.
Terminal aesthetic
Monospace stack, a non-selectable $ prompt, and an indigo command colour give an authentic terminal look.
Debounced feedback
The copied state auto-resets on a cleared timer so rapid copies never leave it stuck.

About this UI Snippet

Code Snippet Tabs — Package-Manager Command Block with Sliding Ink and Copy

Screenshot of the Code Snippet Tabs snippet rendered live

Every library's README and docs page shows the install command, and the polished version offers it for each package manager — npm, pnpm, yarn, bun — behind tabs, with a one-click copy button. This component is that block: a dark terminal-style card with a sliding "ink" underline that animates between tabs, a copy button with success feedback, keyboard navigation, and a monospace command line with a shell prompt. It is built in HTML, CSS, and vanilla JavaScript, and it is the snippet you put at the top of a docs page or component example.

The sliding ink underline

Instead of giving each tab its own static underline, a single .cst-ink element slides beneath the active tab. moveInk() reads the active tab's offsetLeft and offsetWidth and sets the ink's transform: translateX() and width to match. Because both properties are CSS-transitioned, the underline glides and resizes from one tab to the next — the signature animated-tabs effect from Vercel, Stripe, and shadcn/ui docs. Measuring from the live DOM means the ink is always correct regardless of tab label widths (npm and pnpm are different lengths), and a resize listener re-aligns it if the layout reflows.

Swapping the command

The four commands live in a COMMANDS array. Selecting a tab sets the <code> element's textContent to the matching command, toggles the .active class and aria-selected across the tabs, and moves the ink. Using textContent (not innerHTML) means the command is inserted as plain text — safe and correct, with no HTML parsing — which matters when a command could contain characters like & or quotes.

Copy with clipboard fallback

The copy button writes the active command to the clipboard with navigator.clipboard.writeText(), wrapped in a try/catch that falls back to a hidden-textarea document.execCommand('copy') for insecure contexts or sandboxed iframes. On success it adds a .copied class that swaps the copy icon for a green checkmark via pure CSS, and a debounced setTimeout reverts it after 1.7 seconds. Crucially, copy always reads from the COMMANDS array for the current tab, so you copy exactly what is shown — switch to yarn, hit copy, and you get the yarn command.

Keyboard-navigable tablist

The tabs are role="tab" inside a role="tablist", and the active tab carries aria-selected="true". Arrow Left and Arrow Right move the selection (with wrap-around via modulo) and shift focus to the next tab, the keyboard pattern expected of a tablist. Every tab is a real <button>, so the whole control is operable without a mouse.

The terminal aesthetic

The card uses a deep navy background, a monospace font stack (ui-monospace, 'SF Mono', Menlo), a dimmed $ shell prompt that is user-select: none so it is not copied when a user selects the line by hand, and an indigo-tinted command colour. The whole thing reads as a real terminal snippet, which is the visual language developers expect for install instructions.

Customisation

Edit the tab labels and the COMMANDS array together (keep them in the same order). You are not limited to install commands — use it for any set of equivalent snippets (cURL vs fetch vs axios, or SQL dialects). For multi-line code, swap the single <code> for a block and the same select/copy logic applies. Swap the #818cf8 ink and #a5b4fc command colour for your palette, and adjust the ink transition duration to taste.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than assuming the sliding underline is just a CSS transition, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why moveInk() reads offsetLeft and offsetWidth live from the DOM instead of hardcoding pixel positions per tab, and why that specific approach handles tabs of different label lengths (npm versus pnpm) correctly. The same assistant can help you stress-test it — ask what happens to the ink's position if the window is resized while a tab other than the first is active, and confirm the resize listener actually recomputes from the currently active tab rather than resetting to the first one. It's also a good partner for extending the block: ask it to persist the last-selected package manager in localStorage so returning visitors see their preferred tab, add a fifth tab for a different tool, or generalize the component so COMMANDS could hold multi-line snippets instead of single install commands. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "package manager install command" tab block with a sliding underline in plain HTML, CSS, and JavaScript — no animation library.

Requirements:
- A row of tab buttons (e.g. npm, pnpm, yarn, bun) inside a proper ARIA tablist (role="tablist" on the container, role="tab" and aria-selected on each button), with a single shared underline element positioned absolutely beneath the tabs rather than each tab having its own border.
- On selecting a tab, measure that specific tab's offsetLeft and offsetWidth directly from the live DOM and set the shared underline's transform (translateX) and width to match those exact values, with both properties CSS-transitioned so the underline visibly glides and resizes between tabs of different label lengths.
- Re-run that same measurement on window resize so the underline stays correctly aligned under the currently active tab if the layout reflows, not just on initial load.
- Store the actual commands in a plain array indexed to match the tab order, and when a tab is selected, set the displayed command via textContent (not innerHTML) so special characters in a command render literally with no HTML parsing risk.
- Support Left and Right arrow key navigation while focus is inside the tablist: pressing an arrow key must move the selection with wrap-around at both ends, update the displayed command and underline, and move keyboard focus to the newly selected tab.
- A copy button that always copies the array entry corresponding to the currently active tab (not scraped text from the page) via the Clipboard API with a hidden-textarea execCommand fallback, swapping its icon to a checkmark for roughly 1.5-2 seconds using a debounced timer that's cleared and restarted on rapid repeated clicks.
- Style a shell-prompt character before the command as non-selectable (so manually selecting the command text with a mouse never includes the prompt).

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste the HTML, CSS, and JSA dark command card renders with npm/pnpm/yarn/bun tabs, an ink underline under npm, and a copy button.
  2. 2
    Click a package-manager tabThe ink underline slides and resizes to the new tab and the command line updates to that manager's install command.
  3. 3
    Use arrow keysFocus a tab and press Left/Right to move between managers with wrap-around; focus follows the selection.
  4. 4
    Click copyThe current command is copied to the clipboard and the icon turns into a green checkmark for ~1.7 seconds.
  5. 5
    Set your commandsEdit the tab labels and the COMMANDS array (same order) to your package name or any equivalent snippet set.
  6. 6
    Theme itSwap the ink and command colours and adjust the ink transition duration to match your docs.

Real-world uses

Common Use Cases

Library and package docs
Show install commands for every package manager at the top of a README or docs page — pair with a code block for usage examples below.
Component and design-system sites
Offer the install snippet behind tabs the way shadcn/ui and Radix docs do; complements code block tabs for multi-file examples.
API and SDK quickstarts
Switch between language or client snippets (cURL, fetch, axios) using the same tabbed copy pattern.
Tutorials and onboarding
Give learners a copy-ready command for their tool of choice without cluttering the page with all four.
CLI and tooling landing pages
Lead with a slick install block as the hero CTA for a developer tool.
Learning animated tabs
A reference for the sliding-ink technique and clipboard copy; compare with animated tabs for content panels.

Got questions?

Frequently Asked Questions

moveInk() reads the active tab's offsetWidth and offsetLeft directly from the rendered DOM and sets the ink's width and translateX to match. Because it measures live, the underline fits labels of any length (npm vs pnpm vs yarn) exactly, and a window resize listener re-runs it so the ink stays aligned if the layout changes. Both width and transform are CSS-transitioned, which produces the glide-and-resize effect.

Yes. The copy handler reads COMMANDS[active] — the command for the currently selected tab — rather than scraping the DOM, so it always copies exactly what is shown. Switch to yarn and copy, and you get the yarn command. The async Clipboard API does the copy, with a hidden-textarea execCommand fallback for environments where the Clipboard API is blocked.

Yes. Replace the single <code> line with a multi-line <pre><code> block and set its textContent per tab from the COMMANDS array (each entry can contain newlines). The tab switching, ink animation, keyboard nav, and copy logic are unchanged — only the content area grows. For syntax highlighting, run a highlighter over the code after each select().

The prompt span has user-select: none, so a manual text selection skips it — you select only the command, not the shell prefix. The copy button is even safer because it copies from the COMMANDS array, which never includes the prompt at all. Both paths give you a clean, paste-ready command.

Hold the active index in state and render the command from a COMMANDS array. For the sliding ink, use a ref to the active tab and an effect that, when the index changes, reads its offsetLeft/offsetWidth and sets the ink style — re-run it on resize too. The copy handler copies COMMANDS[active] with the same fallback. Bind .active/aria-selected to index comparisons; the keyboard handler attaches to the tablist's onKeyDown.