Skip to content

Configurable CSV separator for Excel locale compatibility #521

@grunk

Description

@grunk

Problem Statement

CSV downloads from Streamdown tables always use , as the field separator. On systems with European locales (FR, DE, ES, IT, …), Excel uses the locale's list separator typically ; when opening .csv files. As a result, files exported from Streamdown open in Excel with every row crammed into a single cell, forcing end-users to manually re-import via "Data → From Text/CSV" and pick the delimiter themselves. Numbers and Google Sheets auto-detect the separator, so the issue is Excel-specific but very visible to non-English users.

Proposed Solution

Make the CSV separator configurable, with two complementary mechanisms:

  1. Expose an option on tableDataToCSV and on TableDownloadButton / TableDownloadDropdown to set the separator explicitly (e.g. csvSeparator: ',' | ';' | '\t', defaulting to ,).

  2. Optionally support an "auto" value that picks the separator from the user's locale via Intl.NumberFormat().formatToParts(1.1): if the decimal separator is ,, use ; as the field separator; otherwise use ,. This mirrors the rule Excel itself applies to choose its list separator and resolves the issue for the vast majority of affected users.

Escaping logic should apply against whichever separator is selected (i.e. a value containing ; must be quoted when the separator is ;, per RFC 4180 generalized to the chosen delimiter).

Alternatives Considered

Using the sep=, directive before header would work in Excel but breaks in lot other situation.

Right now we can overcome this limitation by overriding the default table component and making it use our custom csv function but it feels overkill just to change a separator

const streamdownComponents = { table: StreamdownTable }; // Rewrite of the table components just to handle separator change
const streamdownControls = { code: false, table: false } as const;

    <Streamdown
      components={streamdownComponents}
      controls={streamdownControls}

      {...props}
    />

Use Case

<Streamdown
  controls={{
    table: {
      csvSeparator: ",", // ";" , "auto"
    }
  }}
>
  {markdown}
</Streamdown>

Priority

Nice to have

Contribution

  • I am willing to help implement this feature

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions