CodeBlock Component Showcase

By Jay Griffin  ·  January 21, 2026*Updated 2 times:
  1. February 2, 2026
  2. February 3, 2026
🏷️ Tags:devcomponentstesting

Testing and showcasing all CodeBlock component configurations including bash/shell and markdown support

CodeBlock Component Showcase

Testing all possible CodeBlock configurations with the new filename and icon features.

Copy Button Hover Behavior

One of the most nuanced interactions I've implemented is the copy button's visibility logic. The goal was to create behavior that feels natural and provides clear feedback without being distracting or confusing.

The Requirements:

1. The copy button should only appear when hovering over a code block (reduces visual clutter)

2. When clicked, the button transforms into a checkmark to confirm the copy succeeded

3. The checkmark must remain visible even if you move your cursor away from the code block (otherwise the user never sees the confirmation)

4. After ~2 seconds, the checkmark transitions back to the copy button icon

5. Here's the tricky part: if your cursor is still on the code block when it transitions back, the copy button should remain visible. But if your cursor moved away, the copy button should immediately disappear without any flash or brief visibility.

The Technical Challenge:

CSS transitions create a problem here. When the button switches from checkmark back to copy icon, it needs different visibility behavior depending on hover state:

The issue is that a transition on opacity means there's a brief moment where the copy button fades out, creating a flash of visibility even when you're not hovering.

The Solution:

I used a combination of data attributes and conditional CSS transitions. The button has adata-copied attribute that tracks whether it's showing the checkmark or copy icon. Whendata-copied="false" (transitioning back to copy icon), I apply transition: none which makes the opacity change instant rather than animated. This means:

Additionally, I render both SVG icons simultaneously with crossfading opacity transitions. This eliminates the jarring flash that happens when you conditionally render one or the other.

The result is an interaction that feels completely natural - the copy button never flashing briefly, and the checkmark confirmation is always visible long enough to register.

Transition Timing Details

Getting the timing right was critical for the feel of the interaction. The copy button uses:

Base transition: transition: opacity 0.25s ease 0.15s

This means when you hover over the code block, the button waits 0.15 seconds (delay) before starting to fade in, then takes 0.25 seconds to complete the fade. Total time from hover to fully visible: 0.4 seconds.

The instant-hide logic: &:not(:hover) button[data-copied="false"]

When the code block is NOT being hovered AND the button is in copy mode (not checkmark mode), we apply transition: none. This selector is key - it only matches when both conditions are true, which means:

The 0.15s delay prevents the button from flashing briefly as your cursor sweeps across the page. You have to intentionally hover on the code block for a moment before the button appears, which feels more deliberate and less distracting.

TypeScript Files

example.ts
interface User {
  id: string;
  name: string;
  email: string;
}

function getUser(id: string): User {
  return { id, name: 'John', email: 'john@example.com' };
}

TSX/React Files

Button.tsx
export function Button({ children, onClick }: ButtonProps) {
  return (
    <button onClick={onClick} className="btn">
      {children}
    </button>
  );
}

JavaScript Files

utils.js
function formatDate(date) {
  return new Intl.DateTimeFormat('en-US').format(date);
}

module.exports = { formatDate };

JSX Files

Card.jsx
export function Card({ title, content }) {
  return (
    <div className="card">
      <h3>{title}</h3>
      <p>{content}</p>
    </div>
  );
}

CSS Files

styles.css
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem;
}

.btn {
  background: #007bff;
  color: white;
  border: none;
  padding: 0.5rem 1rem;
  border-radius: 4px;
}

HTML Files

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example Page</title>
</head>
<body>
  <h1>Hello World</h1>
</body>
</html>

Markdown Files

README.md
# Project Title

A brief description of the project.

## Features

- **Feature 1**: Does something amazing
- **Feature 2**: Does something else
- Feature 3

## Installation

```bash
npm install my-package
```

## Usage

Here's how to use it:

```typescript
import { MyComponent } from 'my-package';

const app = <MyComponent />;
```

## Links

- [Documentation](https://example.com/docs)
- [GitHub](https://github.com/example/repo)

> **Note:** This is an important callout.

---

Made with ❤️ by the team

Using language="md":

CONTRIBUTING.md
# Contributing Guidelines

Thank you for contributing!

## Pull Request Process

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing`)
5. Open a Pull Request

### Code Style

- Use TypeScript
- Follow ESLint rules
- Write tests for new features

**Important:** All PRs must pass CI checks.

Bash/Shell Scripts

Using language="bash":

deploy.sh
#!/bin/bash

# Deploy script
echo "Starting deployment..."

npm install
npm run build

if [ $? -eq 0 ]; then
  echo "Build successful!"
  npm start
else
  echo "Build failed!"
  exit 1
fi

Using language="shell":

.sh
# Common shell commands
git add .
git commit -m "feat: add new feature"
git push origin main

# Environment setup
export NODE_ENV=production
export PORT=3000

Using language="sh":

setup.sh
#!/bin/sh
# Minimal POSIX shell script
cd /usr/local/bin
ln -s /opt/app/cli ./app
chmod +x ./app

Without Filename (Language Fallback)

.ts
// No filename prop, should show "typescript"
const greeting: string = 'Hello, World!';
console.log(greeting);

Without Header

// Header hidden completely
const result = 42;

Edge Cases

No language specified (plain text):

Plain text code block
Should show "text" in header

Unknown file extension:

readme.txt
Text file with no icon
Should show filename without icon

Long bash command (word wrapping test):

.sh
# Really long commands
docker run -d --name my-container --restart unless-stopped -p 8080:8080 -v /host/path:/container/path -e DATABASE_URL=postgresql://user:password@localhost:5432/dbname my-image:latest

# Piped commands
cat /var/log/syslog | grep -i error | awk '{print $1, $2, $3}' | sort | uniq -c | sort -rn | head -20