Skip to content

feat: make code block header action buttons sticky (copy/download)#401

Merged
haydenbleasel merged 5 commits intovercel:mainfrom
aradhyacp:feat/add-sticky-button-code-block
Feb 18, 2026
Merged

feat: make code block header action buttons sticky (copy/download)#401
haydenbleasel merged 5 commits intovercel:mainfrom
aradhyacp:feat/add-sticky-button-code-block

Conversation

@aradhyacp
Copy link
Contributor

@aradhyacp aradhyacp commented Feb 18, 2026

Description

Add sticky behavior to the action buttons (copy/download) in the CodeBlockHeader, ensuring that these controls remain visible and easily accessible while scrolling through long code blocks.
The language label and overall header layout are unaffected, preserving the original design while improving usability for users interacting with large snippets.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Refactoring (no functional changes)

Related Issues

Fixes #113
Closes #113
Related to #113

Changes Made

  • Made the action buttons in CodeBlockHeader sticky
  • Buttons remain pinned while scrolling code content
  • Pre-existing language label remains unaffected

Testing

  • All existing tests pass
  • Added new tests for the changes
  • Manually tested the changes

Test Coverage

Manually tested the sticky buttons with long code blocks
How I tested it locally:

I wanted to verify my changes, so I linked the local package into a test React app:

# In the streamdown repo
pnpm build
pnpm link

# In my test project
pnpm link streamdown

Then I used the following test component:

import React from 'react'
import { Streamdown } from 'streamdown';
import "streamdown/styles.css";
import { code } from "@streamdown/code";


const App = () => {
  const markdown = `
\`\`\`ts
function binarySearch<T>(arr: T[], target: T, compare: (a: T, b: T) => number = (a, b) => a < b ? -1 : a > b ? 1 : 0): number {
    let left = 0;
    let right = arr.length - 1;

    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        const comparison = compare(target, arr[mid]);

        if (comparison === 0) {
            return mid; // Found the target
        } else if (comparison < 0) {
            right = mid - 1; // Search left half
        } else {
            left = mid + 1; // Search right half
        }
    }

    return -1; // Target not found
}

// Example usage:
const numbers = [1, 3, 5, 7, 9, 11, 13];
const target = 7;
const result = binarySearch(numbers, target);
console.log(\`Index of \${target}: \${result}\`); // Output: Index of 7: 3

// For custom objects
interface Item {
    id: number;
    name: string;
}

const items: Item[] = [
    { id: 1, name: "Apple" },
    { id: 2, name: "Banana" },
    { id: 3, name: "Orange" }
];

const targetItem = { id: 2, name: "Banana" };
const index = binarySearch(items, targetItem, (a, b) => a.id - b.id);
console.log(\`Index of item with id 2: \${index}\`); // Output: Index of item with id 2: 1
console.log("this a test");
console.log("this a test");
console.log("this a test");
console.log("this a test");
console.log("this a test");
console.log("this a test");
console.log("this a test");
console.log("this a test");
console.log("this a test");
console.log("this a test");
\`\`\`
`;

  return (
    <div className="App">
      <div className="mx-auto mt-5 w-200">
      <Streamdown plugins={{ code: code }}>{markdown}</Streamdown>
      </div>
    </div>
  )
}

export default App

Screenshots/Demos

Before

Screen.Recording.2026-02-18.at.1.06.51.PM.mp4

After

stickyafter2.mp4

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have created a changeset (pnpm changeset)

Changeset

  • I have created a changeset for these changes

Additional Notes

This change only affects the action buttons in the code block header.
I’m happy to receive feedback as I’m still learning and improving.

Thank you :)

@vercel
Copy link
Contributor

vercel bot commented Feb 18, 2026

@aradhyacp is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@haydenbleasel
Copy link
Contributor

just gave it a try locally. 10/10 love it. 🚀

@haydenbleasel haydenbleasel merged commit d73d7bb into vercel:main Feb 18, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sticky action buttons in code block

2 participants