How to download CSV and JSON files in React

By Thomas Findlay 27 Aug, 2021

There are websites that let users download CSV or JSON data as a file. This functionality can be quite useful, as users can download the data for further processing or to share it. In this article, you will learn how to add the functionality that will allow users to export a table in React and download it in JSON and CSV formats.

You can find the full code example in the GitHub repo. The code is also available in the interactive CodeSandbox example below. However, note that the files won't be downloaded there due to the fact that the code in the CodeSandbox runs in an isolated environment.

Project Setup

First, let's create a new React project using Vite.

npm init vite@latest csv-json-files-download -- --template react

After the project is created, cd into it to install dependencies by running npm install and then start the dev server with npm run dev.

Next, we need to modify the App.jsx and App.css files.

src/App.jsx

import React from 'react'

function App() {
  return (
    <div className='App'>
      <h1>How to download CSV and JSON files in React</h1>
    </div>
  )
}

export default App

src/App.css

.App {
  max-width: 40rem;
  margin: 2rem auto;
}

That's enough for the initial setup. Let's start by adding functionality to export to JSON.

Export to JSON

Let's start by creating a file with users data that will be used for downloading a file and rendering a table.

src/users.json

{
  "users": [
    {
      "id": 1,
      "name": "Caitlyn",
      "surname": "Kerluke",
      "age": 24
    },
    {
      "id": 2,
      "name": "Rowan ",
      "surname": "Nikolaus",
      "age": 45
    },
    {
      "id": 3,
      "name": "Kassandra",
      "surname": "Haley",
      "age": 32
    },
    {
      "id": 4,
      "name": "Rusty",
      "surname": "Arne",
      "age": 58
    }
  ]
}

Next, we need to update the App component to utilise the users data and display it in a table. Besides that, we will add a button to trigger the download. Below you can see the code for the App.jsx component. Besides the component. we have two functions: exportToJson and downloadFile. The former one calls the latter with appropriate arguments. The downloadFile function accepts an object as a parameter and expects three properties:

  • data
  • fileName
  • fileType

The data and fileType are used to create a blob that is downloaded. After that, we create an anchor element and dispatch a click event on it.

src/App.jsx

import React from 'react'
import './App.css'
import usersData from './users.json'

const downloadFile = ({ data, fileName, fileType }) => {
  // Create a blob with the data we want to download as a file
  const blob = new Blob([data], { type: fileType })
  // Create an anchor element and dispatch a click event on it
  // to trigger a download
  const a = document.createElement('a')
  a.download = fileName
  a.href = window.URL.createObjectURL(blob)
  const clickEvt = new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true,
  })
  a.dispatchEvent(clickEvt)
  a.remove()
}

const exportToJson = e => {
  e.preventDefault()
  downloadFile({
    data: JSON.stringify(usersData.users),
    fileName: 'users.json',
    fileType: 'text/json',
  })
}

function App() {
  return (
    <div className='App'>
      <h1>How to download CSV and JSON files in React</h1>

      <table className='usersTable'>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Surname</th>
            <th>Age</th>
          </tr>
        </thead>
        <tbody>
          {usersData.users.map(user => {
            const { id, name, surname, age } = user
            return (
              <tr key={id}>
                <td>{id}</td>
                <td>{name}</td>
                <td>{surname}</td>
                <td>{age}</td>
              </tr>
            )
          })}
        </tbody>
      </table>
      <div className='actionBtns'>
        <button type='button' onClick={exportToJson}>
          Export to JSON
        </button>
      </div>
    </div>
  )
}

export default App

We can add a few styles, so the table looks a bit nicer.

src/App.css

.App {
  max-width: 40rem;
  margin: 2rem auto;
}

.usersTable th,
.usersTable td {
  padding: 0.4rem 0.6rem;
  text-align: left;
}

.actionBtns {
  margin-top: 1rem;
}

.actionBtns button + button {
  margin-left: 1rem;
}

Great, now you should be able to download the users data as a JSON file by clicking on the Export to JSON button. Next, we will add Export to CSV functionality.

Export to CSV

We need another button that will be used to export data to a CSV file. Besides that, we also need a handler for it. The usersData is in the JSON format, so we will need to convert it to the CSV format, before passing it to the downloadFile function.

src/App.jsx

import React from 'react'
import './App.css'
import usersData from './users.json'

const downloadFile = ({ data, fileName, fileType }) => {
  const blob = new Blob([data], { type: fileType })

  const a = document.createElement('a')
  a.download = fileName
  a.href = window.URL.createObjectURL(blob)
  const clickEvt = new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true,
  })
  a.dispatchEvent(clickEvt)
  a.remove()
}

const exportToJson = e => {
  e.preventDefault()
  downloadFile({
    data: JSON.stringify(usersData.users),
    fileName: 'users.json',
    fileType: 'text/json',
  })
}

const exportToCsv = e => {
  e.preventDefault()

  // Headers for each column
  let headers = ['Id,Name,Surname,Age']

  // Convert users data to a csv
  let usersCsv = usersData.users.reduce((acc, user) => {
    const { id, name, surname, age } = user
    acc.push([id, name, surname, age].join(','))
    return acc
  }, [])

  downloadFile({
    data: [...headers, ...usersCsv].join('\n'),
    fileName: 'users.csv',
    fileType: 'text/csv',
  })
}

function App() {
  return (
    <div className='App'>
      <h1>How to download CSV and JSON files in React</h1>

      <table className='usersTable'>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Surname</th>
            <th>Age</th>
          </tr>
        </thead>
        <tbody>
          {usersData.users.map(user => {
            const { id, name, surname, age } = user
            return (
              <tr key={id}>
                <td>{id}</td>
                <td>{name}</td>
                <td>{surname}</td>
                <td>{age}</td>
              </tr>
            )
          })}
        </tbody>
      </table>
      <div className='actionBtns'>
        <button type='button' onClick={exportToJson}>
          Export to JSON
        </button>
        <button type='button' onClick={exportToCsv}>
          Export to CSV
        </button>
      </div>
    </div>
  )
}

export default App

Wrap up

There we have it. I hope you enjoyed this article. Now you should be well equipped with knowledge on how to add download files functionality to your own projects. Remember that even though I used React to demonstrate the download examples, you can use the download logic in other frameworks like Vue, Svelte, or Angular.


Want to stay up to date and learn more programming tips? Make sure to follow me on Twitter and subscribe to the newsletter below!


Want to learn something new?

Subscribe to the newsletter!


Thomas Findlay photo

About author

Thomas Findlay is a 5 star rated mentor, full-stack developer, consultant, and technical writer. He works with many different technologies such as JavaScript, Vue, Nuxt, React, Next, React Native, Node.js, Python, PHP, and more. He has obtained MSc in Advanced Computer Science degree with Distinction at Exeter University, as well as First-Class BSc in Web Design & Development at Northumbria University.

Over the years, Thomas has worked with many developers and teams from beginners to advanced and helped them build and scale their applications and products. He also mentored a lot of developers and students, and helped them progress in their careers.

To get to know more about Thomas you can check out his Codementor and Twitter profiles.