Skip to content

feat: add configurable base filename for code block downloads#559

Open
aradhyacp wants to merge 5 commits into
vercel:mainfrom
aradhyacp:feat/make-download-file-names-customizable
Open

feat: add configurable base filename for code block downloads#559
aradhyacp wants to merge 5 commits into
vercel:mainfrom
aradhyacp:feat/make-download-file-names-customizable

Conversation

@aradhyacp

@aradhyacp aradhyacp commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Description

Adds support for configuring the base filename used by the built-in code block download button.

Previously, downloaded files were always named file., where the extension was inferred from the detected language (for example file.ts, file.py, file.json). This change allows consumers to specify a custom base filename while preserving Streamdown's existing language-to-extension mapping.

The implementation intentionally focuses on a configurable base filename rather than supporting dynamic filename generation or code-fence metadata.

While code-fence metadata (for example ```ts title=main.ts ) is a reasonable source for filenames, it is not consistently emitted by AI assistants. Many popular AI chatbots—including major providers—typically output fenced code blocks without metadata, making it an unreliable source for default filenames. A simple configurable base filename provides a predictable solution that works regardless of where the markdown originates.

The existing language detection continues to determine the correct file extension automatically, so users only need to configure the filename prefix.

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 #558
Closes #558
Related to #558

Changes Made

  • Added a new codeDownload configuration to Streamdown
  • Added support for configuring the base filename via codeDownload.baseFileName
  • Preserved existing language → extension mapping (.ts, .py, .tsx, etc.)
  • Exposed the configuration through StreamdownContext to avoid prop drilling
  • Kept the existing default behavior (file.) when no configuration is provided

Testing

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

Test Coverage

Test component:

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

const App = () => {
  const markdown = `
  \`\`\`tsx
  import React from "react";

export function Button() {
  return (
    <button type="button" onClick={() => console.log("Clicked!")}>
      Click me
    </button>
  );
}
\`\`\`
`;

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

export default App;

Verified that downloads produce:

  • customFileName.tsx

When codeDownload is omitted, the existing behavior remains unchanged:

  • file.tsx

Screenshots/Demos

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 PR intentionally does not introduce support for filename generation from code-fence metadata (for example title=main.ts)

The goal of this change is to provide a simple and reliable API that works consistently across markdown produced by different sources. Since many AI assistants do not emit code-fence metadata, relying on it would not provide a dependable default experience. Likewise, callback-based filename generation adds API complexity for a use case that can already be addressed by configuring a base filename while continuing to infer the correct extension automatically.

Future enhancements can build on this API if broader filename customization becomes a common request.

…and context

- Introduced CodeDownloadConfig interface to define optional baseFileName for code downloads.
- Updated StreamdownProps to include codeDownload property.
- Enhanced StreamdownContextType to support codeDownload configuration.
- Ensured default values are set for new properties in the context.
… codeDownload configuration

- Modified filename logic in CodeBlockDownloadButton to utilize baseFileName from StreamdownContext.
- Ensured fallback to default filename if baseFileName is not provided.
…lename scenarios

- Added tests to verify the functionality of custom baseFileName in the download button.
- Included cases for handling undefined codeDownload, unknown languages, and special characters in filenames.
- Ensured that the button is enabled and the correct filename is used during the download process.
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

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

A member of the Team first needs to authorize it.

…nd component usage

- Simplified the rendering of CodeBlockDownloadButton by consolidating props into a single line.
- Updated test assertions for expected save calls to improve readability and maintainability.
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.

CodeBlockDownloadButton: filename/MIME not overridable (always file.<ext>, table download has filename — code doesn't)

1 participant