How to export tables to CSV in React

CSV export enables users to analyze table data in spreadsheet applications, share data with stakeholders, and create backups of displayed information. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented data export functionality in admin dashboards throughout my 11 years of frontend development. The most straightforward approach is converting table data to CSV format and triggering a browser download using Blob URLs. This method works client-side without server dependencies and handles various data types including strings, numbers, and special characters.

Convert data array to CSV string format, create Blob URL, trigger download with temporary anchor element.

const ExportableTable = ({ data }) => {
  const convertToCSV = (data) => {
    if (!data || data.length === 0) return ''

    const headers = Object.keys(data[0])
    const csvRows = []

    csvRows.push(headers.join(','))

    for (const row of data) {
      const values = headers.map(header => {
        const value = row[header]
        const escaped = ('' + value).replace(/"/g, '\\"')
        return `"${escaped}"`
      })
      csvRows.push(values.join(','))
    }

    return csvRows.join('\n')
  }

  const downloadCSV = () => {
    const csvContent = convertToCSV(data)
    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
    const url = URL.createObjectURL(blob)
    const link = document.createElement('a')

    link.setAttribute('href', url)
    link.setAttribute('download', `table-export-${new Date().getTime()}.csv`)
    link.style.visibility = 'hidden'

    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)

    URL.revokeObjectURL(url)
  }

  return (
    <div>
      <button onClick={downloadCSV}>
        Export to CSV
      </button>

      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Role</th>
          </tr>
        </thead>
        <tbody>
          {data.map(user => (
            <tr key={user.id}>
              <td>{user.id}</td>
              <td>{user.name}</td>
              <td>{user.email}</td>
              <td>{user.role}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

Here the convertToCSV function extracts headers from the first data object using Object.keys. The function iterates through each data row, escaping double quotes and wrapping values in quotes to handle commas and special characters correctly. The csvRows array builds the complete CSV string with headers first, then data rows, joined by newlines. The downloadCSV function creates a Blob with proper MIME type for CSV files. A temporary anchor element is created programmatically, configured with the Blob URL and timestamp-based filename. The click is triggered automatically, then the element and URL are cleaned up to prevent memory leaks.

Best Practice Note:

This is the CSV export approach we use in CoreUI admin templates for reliable data export functionality across browsers. Handle large datasets by implementing chunked processing to avoid blocking the UI thread, add UTF-8 BOM character (\uFEFF) at the start of CSV content for proper Excel compatibility with special characters, and consider using libraries like Papa Parse for advanced CSV generation with custom delimiters and formatting options.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
How to Convert a Map to an Array in JavaScript
How to Convert a Map to an Array in JavaScript

How to Remove Elements from a JavaScript Array
How to Remove Elements from a JavaScript Array

How to replace all occurrences of a string in JavaScript?
How to replace all occurrences of a string in JavaScript?

JavaScript Template Literals: Complete Developer Guide
JavaScript Template Literals: Complete Developer Guide

Answers by CoreUI Core Team