react-papaparse

The powerful, in-browser React CSV parser for big boys and girls

  Install  Demo  Documentation
Version
4

Features

Now the fastest React CSV parser for the browser

The world's first multi-threaded CSV parser for the browser

react-papaparse can handle files gigabytes in size without crashing

Use react-papaparse when performance, privacy, and correctness matter to you

react-papaparse alleviates privacy concerns related to uploading files

Malformed CSV is handled gracefully with a detailed error report

  • Stream local and remote files
  • Multi-threaded
  • Header row support
  • Type conversion
  • Skip commented lines
  • Fast mode and easy to use
  • Graceful error handling
  • CSVDownloader


  • Frameworks

    react-papaparse strongly support Next.js and other React frameworks. react-papaparse is the fastest React CSV parser for the browser (only works in the browser), so you need to set the component with no SSR (server-side render) in case you use readRemoteFile function.

    People react-papaparse

    react-papaparse react-papaparse

    CSV Parsing

    "Isn't parsing CSV just String.split(',')?"

    react-papaparse does it right. Just pass in the CSV string with an optional configuration.

    import React from 'react';
    
    import { usePapaParse } from 'react-papaparse';
    
    export default function ReadString() {
      const { readString } = usePapaParse();
    
      const handleReadString = () => {
        const csvString = 'Column 1,Column 2,Column 3,Column 4
    1-1,1-2,1-3,1-4
    2-1,2-2,2-3,2-4
    3-1,3-2,3-3,3-4
    4,5,6,7';
    
        readString(csvString, {
          worker: true,
          complete: (results) => {
            console.log('---------------------------');
            console.log(results);
            console.log('---------------------------');
          },
        });
      };
    
      return <button onClick={() => handleReadString()}>readString</button>;
    }
    
    /*
    results = {
      data: [ ... ],    // parsed data
      errors: [ ... ],  // errors encountered
      meta: { ... }     // extra parse info
    }
    */

    Delimiter Detection

    "But I don't know the delimiter..."

    That's okay. react-papaparse will scan the first few rows to find the right delimiter.

    const config = {
      worker: true,
      complete: (results) => {
        console.log('---------------------------');
        console.log(results.meta.delimiter);
        console.log('---------------------------');
      },
    };
    
    readString(csvString, config);
    
    // "\t"

    Local Files

    "Great, but I have a file to parse."

    Then use CSVReader component instead of readString method. Since file parsing is asynchronous, don't forget callback methods.

    Basic Upload
    Basic Upload
    import React, { CSSProperties } from 'react';
    
    import { useCSVReader } from 'react-papaparse';
    
    const styles = {
      csvReader: {
        display: 'flex',
        flexDirection: 'row',
        marginBottom: 10,
      } as CSSProperties,
      browseFile: {
        width: '20%',
      } as CSSProperties,
      acceptedFile: {
        border: '1px solid #ccc',
        height: 45,
        lineHeight: 2.5,
        paddingLeft: 10,
        width: '80%',
      } as CSSProperties,
      remove: {
        borderRadius: 0,
        padding: '0 20px',
      } as CSSProperties,
      progressBarBackgroundColor: {
        backgroundColor: 'red',
      } as CSSProperties,
    };
    
    export default function CSVReader() {
      const { CSVReader } = useCSVReader();
    
      return (
        <CSVReader
          onUploadAccepted={(results: any) => {
            console.log('---------------------------');
            console.log(results);
            console.log('---------------------------');
          }}
        >
          {({
            getRootProps,
            acceptedFile,
            ProgressBar,
            getRemoveFileProps,
          }: any) => (
            <>
              <div style={styles.csvReader}>
                <button type='button' {...getRootProps()} style={styles.browseFile}>
                  Browse file
                </button>
                <div style={styles.acceptedFile}>
                  {acceptedFile && acceptedFile.name}
                </div>
                <button {...getRemoveFileProps()} style={styles.remove}>
                  Remove
                </button>
              </div>
              <ProgressBar style={styles.progressBarBackgroundColor} />
            </>
          )}
        </CSVReader>
      );
    }
    Click and Drag Upload
    Click and Drag Upload
    import React, { useState, CSSProperties } from 'react';
    
    import {
      useCSVReader,
      lightenDarkenColor,
      formatFileSize,
    } from 'react-papaparse';
    
    const GREY = '#CCC';
    const GREY_LIGHT = 'rgba(255, 255, 255, 0.4)';
    const DEFAULT_REMOVE_HOVER_COLOR = '#A01919';
    const REMOVE_HOVER_COLOR_LIGHT = lightenDarkenColor(
      DEFAULT_REMOVE_HOVER_COLOR,
      40
    );
    const GREY_DIM = '#686868';
    
    const styles = {
      zone: {
        alignItems: 'center',
        borderWidth: 2,
        borderStyle: 'dashed',
        borderColor: GREY,
        borderRadius: 20,
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
        justifyContent: 'center',
        padding: 20,
      } as CSSProperties,
      file: {
        background: 'linear-gradient(to bottom, #EEE, #DDD)',
        borderRadius: 20,
        display: 'flex',
        height: 120,
        width: 120,
        position: 'relative',
        zIndex: 10,
        flexDirection: 'column',
        justifyContent: 'center',
      } as CSSProperties,
      info: {
        alignItems: 'center',
        display: 'flex',
        flexDirection: 'column',
        paddingLeft: 10,
        paddingRight: 10,
      } as CSSProperties,
      size: {
        backgroundColor: GREY_LIGHT,
        borderRadius: 3,
        marginBottom: '0.5em',
        justifyContent: 'center',
        display: 'flex',
      } as CSSProperties,
      name: {
        backgroundColor: GREY_LIGHT,
        borderRadius: 3,
        fontSize: 12,
        marginBottom: '0.5em',
      } as CSSProperties,
      progressBar: {
        bottom: 14,
        position: 'absolute',
        width: '100%',
        paddingLeft: 10,
        paddingRight: 10,
      } as CSSProperties,
      zoneHover: {
        borderColor: GREY_DIM,
      } as CSSProperties,
      default: {
        borderColor: GREY,
      } as CSSProperties,
      remove: {
        height: 23,
        position: 'absolute',
        right: 6,
        top: 6,
        width: 23,
      } as CSSProperties,
    };
    
    export default function CSVReader() {
      const { CSVReader } = useCSVReader();
      const [zoneHover, setZoneHover] = useState(false);
      const [removeHoverColor, setRemoveHoverColor] = useState(
        DEFAULT_REMOVE_HOVER_COLOR
      );
    
      return (
        <CSVReader
          onUploadAccepted={(results: any) => {
            console.log('---------------------------');
            console.log(results);
            console.log('---------------------------');
            setZoneHover(false);
          }}
          onDragOver={(event: DragEvent) => {
            event.preventDefault();
            setZoneHover(true);
          }}
          onDragLeave={(event: DragEvent) => {
            event.preventDefault();
            setZoneHover(false);
          }}
        >
          {({
            getRootProps,
            acceptedFile,
            ProgressBar,
            getRemoveFileProps,
            Remove,
          }: any) => (
            <>
              <div
                {...getRootProps()}
                style={Object.assign(
                  {},
                  styles.zone,
                  zoneHover && styles.zoneHover
                )}
              >
                {acceptedFile ? (
                  <>
                    <div style={styles.file}>
                      <div style={styles.info}>
                        <span style={styles.size}>
                          {formatFileSize(acceptedFile.size)}
                        </span>
                        <span style={styles.name}>{acceptedFile.name}</span>
                      </div>
                      <div style={styles.progressBar}>
                        <ProgressBar />
                      </div>
                      <div
                        {...getRemoveFileProps()}
                        style={styles.remove}
                        onMouseOver={(event: Event) => {
                          event.preventDefault();
                          setRemoveHoverColor(REMOVE_HOVER_COLOR_LIGHT);
                        }}
                        onMouseOut={(event: Event) => {
                          event.preventDefault();
                          setRemoveHoverColor(DEFAULT_REMOVE_HOVER_COLOR);
                        }}
                      >
                        <Remove color={removeHoverColor} />
                      </div>
                    </div>
                  </>
                ) : (
                  'Drop CSV file here or click to upload'
                )}
              </div>
            </>
          )}
        </CSVReader>
      );
    }
    Drag ( No Click ) Upload
    Drag ( No Click ) Upload
    import React, { useState, CSSProperties } from 'react';
    
    import {
      useCSVReader,
      lightenDarkenColor,
      formatFileSize,
    } from 'react-papaparse';
    
    const GREY = '#CCC';
    const GREY_LIGHT = 'rgba(255, 255, 255, 0.4)';
    const DEFAULT_REMOVE_HOVER_COLOR = '#A01919';
    const REMOVE_HOVER_COLOR_LIGHT = lightenDarkenColor(
      DEFAULT_REMOVE_HOVER_COLOR,
      40
    );
    const GREY_DIM = '#686868';
    
    const styles = {
      zone: {
        alignItems: 'center',
        borderWidth: 2,
        borderStyle: 'dashed',
        borderColor: GREY,
        borderRadius: 20,
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
        justifyContent: 'center',
        padding: 20,
      } as CSSProperties,
      file: {
        background: 'linear-gradient(to bottom, #EEE, #DDD)',
        borderRadius: 20,
        display: 'flex',
        height: 120,
        width: 120,
        position: 'relative',
        zIndex: 10,
        flexDirection: 'column',
        justifyContent: 'center',
      } as CSSProperties,
      info: {
        alignItems: 'center',
        display: 'flex',
        flexDirection: 'column',
        paddingLeft: 10,
        paddingRight: 10,
      } as CSSProperties,
      size: {
        backgroundColor: GREY_LIGHT,
        borderRadius: 3,
        marginBottom: '0.5em',
        justifyContent: 'center',
        display: 'flex',
      } as CSSProperties,
      name: {
        backgroundColor: GREY_LIGHT,
        borderRadius: 3,
        fontSize: 12,
        marginBottom: '0.5em',
      } as CSSProperties,
      progressBar: {
        bottom: 14,
        position: 'absolute',
        width: '100%',
        paddingLeft: 10,
        paddingRight: 10,
      } as CSSProperties,
      zoneHover: {
        borderColor: GREY_DIM,
      } as CSSProperties,
      default: {
        borderColor: GREY,
      } as CSSProperties,
      remove: {
        height: 23,
        position: 'absolute',
        right: 6,
        top: 6,
        width: 23,
      } as CSSProperties,
    };
    
    export default function CSVReader() {
      const { CSVReader } = useCSVReader();
      const [zoneHover, setZoneHover] = useState(false);
      const [removeHoverColor, setRemoveHoverColor] = useState(
        DEFAULT_REMOVE_HOVER_COLOR
      );
    
      return (
        <CSVReader
          onUploadAccepted={(results: any) => {
            console.log('---------------------------');
            console.log(results);
            console.log('---------------------------');
            setZoneHover(false);
          }}
          onDragOver={(event: DragEvent) => {
            event.preventDefault();
            setZoneHover(true);
          }}
          onDragLeave={(event: DragEvent) => {
            event.preventDefault();
            setZoneHover(false);
          }}
          noClick
        >
          {({
            getRootProps,
            acceptedFile,
            ProgressBar,
            getRemoveFileProps,
            Remove,
          }: any) => (
            <>
              <div
                {...getRootProps()}
                style={Object.assign(
                  {},
                  styles.zone,
                  zoneHover && styles.zoneHover
                )}
              >
                {acceptedFile ? (
                  <>
                    <div style={styles.file}>
                      <div style={styles.info}>
                        <span style={styles.size}>
                          {formatFileSize(acceptedFile.size)}
                        </span>
                        <span style={styles.name}>{acceptedFile.name}</span>
                      </div>
                      <div style={styles.progressBar}>
                        <ProgressBar />
                      </div>
                      <div
                        {...getRemoveFileProps()}
                        style={styles.remove}
                        onMouseOver={(event: Event) => {
                          event.preventDefault();
                          setRemoveHoverColor(REMOVE_HOVER_COLOR_LIGHT);
                        }}
                        onMouseOut={(event: Event) => {
                          event.preventDefault();
                          setRemoveHoverColor(DEFAULT_REMOVE_HOVER_COLOR);
                        }}
                      >
                        <Remove color={removeHoverColor} />
                      </div>
                    </div>
                  </>
                ) : (
                  'Drop CSV file here to upload'
                )}
              </div>
            </>
          )}
        </CSVReader>
      );
    }
    Click ( No Drag ) Upload
    Click ( No Drag ) Upload
    import React, { useState, CSSProperties } from 'react';
    
    import {
      useCSVReader,
      lightenDarkenColor,
      formatFileSize,
    } from 'react-papaparse';
    
    const GREY = '#CCC';
    const GREY_LIGHT = 'rgba(255, 255, 255, 0.4)';
    const DEFAULT_REMOVE_HOVER_COLOR = '#A01919';
    const REMOVE_HOVER_COLOR_LIGHT = lightenDarkenColor(
      DEFAULT_REMOVE_HOVER_COLOR,
      40
    );
    const GREY_DIM = '#686868';
    
    const styles = {
      zone: {
        alignItems: 'center',
        borderWidth: 2,
        borderStyle: 'dashed',
        borderColor: GREY,
        borderRadius: 20,
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
        justifyContent: 'center',
        padding: 20,
      } as CSSProperties,
      file: {
        background: 'linear-gradient(to bottom, #EEE, #DDD)',
        borderRadius: 20,
        display: 'flex',
        height: 120,
        width: 120,
        position: 'relative',
        zIndex: 10,
        flexDirection: 'column',
        justifyContent: 'center',
      } as CSSProperties,
      info: {
        alignItems: 'center',
        display: 'flex',
        flexDirection: 'column',
        paddingLeft: 10,
        paddingRight: 10,
      } as CSSProperties,
      size: {
        backgroundColor: GREY_LIGHT,
        borderRadius: 3,
        marginBottom: '0.5em',
        justifyContent: 'center',
        display: 'flex',
      } as CSSProperties,
      name: {
        backgroundColor: GREY_LIGHT,
        borderRadius: 3,
        fontSize: 12,
        marginBottom: '0.5em',
      } as CSSProperties,
      progressBar: {
        bottom: 14,
        position: 'absolute',
        width: '100%',
        paddingLeft: 10,
        paddingRight: 10,
      } as CSSProperties,
      zoneHover: {
        borderColor: GREY_DIM,
      } as CSSProperties,
      default: {
        borderColor: GREY,
      } as CSSProperties,
      remove: {
        height: 23,
        position: 'absolute',
        right: 6,
        top: 6,
        width: 23,
      } as CSSProperties,
    };
    
    export default function CSVReader() {
      const { CSVReader } = useCSVReader();
      const [zoneHover, setZoneHover] = useState(false);
      const [removeHoverColor, setRemoveHoverColor] = useState(
        DEFAULT_REMOVE_HOVER_COLOR
      );
    
      return (
        <CSVReader
          onUploadAccepted={(results: any) => {
            console.log('---------------------------');
            console.log(results);
            console.log('---------------------------');
            setZoneHover(false);
          }}
          onDragOver={(event: DragEvent) => {
            event.preventDefault();
            setZoneHover(true);
          }}
          onDragLeave={(event: DragEvent) => {
            event.preventDefault();
            setZoneHover(false);
          }}
          noDrag
        >
          {({
            getRootProps,
            acceptedFile,
            ProgressBar,
            getRemoveFileProps,
            Remove,
          }: any) => (
            <>
              <div
                {...getRootProps()}
                style={Object.assign(
                  {},
                  styles.zone,
                  zoneHover && styles.zoneHover
                )}
              >
                {acceptedFile ? (
                  <>
                    <div style={styles.file}>
                      <div style={styles.info}>
                        <span style={styles.size}>
                          {formatFileSize(acceptedFile.size)}
                        </span>
                        <span style={styles.name}>{acceptedFile.name}</span>
                      </div>
                      <div style={styles.progressBar}>
                        <ProgressBar />
                      </div>
                      <div
                        {...getRemoveFileProps()}
                        style={styles.remove}
                        onMouseOver={(event: Event) => {
                          event.preventDefault();
                          setRemoveHoverColor(REMOVE_HOVER_COLOR_LIGHT);
                        }}
                        onMouseOut={(event: Event) => {
                          event.preventDefault();
                          setRemoveHoverColor(DEFAULT_REMOVE_HOVER_COLOR);
                        }}
                      >
                        <Remove color={removeHoverColor} />
                      </div>
                    </div>
                  </>
                ) : (
                  'Click to upload'
                )}
              </div>
            </>
          )}
        </CSVReader>
      );
    }

    Remote Files

    "No — I mean, the file isn't on my computer."

    Oh, well then just pass in the URL and — of course — a callback.

    import React from 'react';
    
    import { usePapaParse } from 'react-papaparse';
    
    export default function ReadRemoteFile() {
      const { readRemoteFile } = usePapaParse();
    
      const handleReadRemoteFile = () => {
        readRemoteFile(url, {
          complete: (results) => {
            console.log('---------------------------');
            console.log('Results:', results);
            console.log('---------------------------');
          },
        });
      };
    
      return <button onClick={() => handleReadRemoteFile()}>readRemoteFile</button>;
    }

    Streaming

    "Did I mention the file is huge?"

    That's what streaming is for. Specify a step callback to receive the results row-by-row. This way, you won't load the whole file into memory and crash the browser.

    readRemoteFile(url, {
      step: (row) => {
        console.log('Row:', row.data)
      },
      complete: () => {
        console.log('All done!')
      }
    });

    Multi-Threading

    'Lovely. Now my web page locked up.'

    That happens when a long-running script is executing in the same thread as the page. Use a Worker thread by specifying worker: true. It may take slightly longer, but your page will stay reactive.

    readRemoteFile(bigFileURL, {
      worker: true,
      step: (row) => {
        console.log('Row:', row.data)
      },
      complete: () => {
        console.log('All done!')
      }
    });

    Type Conversion

    "Hey, these numbers are parsed as strings."

    Everything is parsed as strings. If you want numbers and booleans, you can enable dynamic typing to do the conversion for you.

    // Converts numeric/boolean data
    readString(csvString, {
      worker: true,
      complete: (results) => {
        console.log(results)
      },
      dynamicTyping: true
    })

    Comments

    "I forgot to mention: my CSV files have comments in them."

    Okay, first off: that's really weird. But fortunately, you can skip those lines... just specify the comment string.

    // Mostly found in academia, some CSV files
    // may have commented lines in them
    readString(csvString, {
      worker: true,
      complete: (results) => {
        console.log(results)
      },
      comments: '#'
    })

    Error Handling

    "Aw, shoot. Errors."

    react-papaparse handles errors pretty well. The CSV standard is somewhat loose ambiguous, so react-papaparse is designed for edge cases. For example, mismatched fields won't break parsing.

    // Example error:
    {
      type: 'FieldMismatch',
      code: 'TooManyFields',
      message: 'Expected 3 fields, but parsed 4',
      row: 1
    }

    JSON to CSV

    "Last thing: what about converting JSON to CSV?"

    Use jsonToCSV() function, passing in your array of arrays or array of objects. react-papaparse will figure it out.

    // Output is a properly-formatted CSV string.
    
    import React from 'react';
    
    import { usePapaParse } from 'react-papaparse';
    
    export default function JsonToCSV() {
      const { jsonToCSV } = usePapaParse();
    
      const handleJsonToCSV = () => {
        const jsonData = [
          {
              "Column 1": "1-1",
              "Column 2": "1-2",
              "Column 3": "1-3",
              "Column 4": "1-4"
          },
          {
              "Column 1": "2-1",
              "Column 2": "2-2",
              "Column 3": "2-3",
              "Column 4": "2-4"
          },
          {
              "Column 1": "3-1",
              "Column 2": "3-2",
              "Column 3": "3-3",
              "Column 4": "3-4"
          },
          {
              "Column 1": 4,
              "Column 2": 5,
              "Column 3": 6,
              "Column 4": 7
          }
        ];
        const results = jsonToCSV(jsonData);
        console.log('---------------------------');
        console.log('Results:', results);
        console.log('---------------------------');
      };
    
      return <button onClick={() => handleJsonToCSV()}>jsonToCSV</button>;
    }

    CSVDownloader

    "Allow to download CSV file from js object."

    Just pass in the js object with an optional configuration ( setting delimiter / separator ).

    import React from 'react';
    
    import { useCSVDownloader } from 'react-papaparse';
    
    export default function CSVDownloader() {
      const { CSVDownloader, Type } = useCSVDownloader();
    
      return (
        <CSVDownloader
          type={Type.Button}
          filename={'filename'}
          bom={true}
          config={{
            delimiter: ';',
          }}
          data={[
            {
              'Column 1': '1-1',
              'Column 2': '1-2',
              'Column 3': '1-3',
              'Column 4': '1-4',
            },
            {
              'Column 1': '2-1',
              'Column 2': '2-2',
              'Column 3': '2-3',
              'Column 4': '2-4',
            },
            {
              'Column 1': '3-1',
              'Column 2': '3-2',
              'Column 3': '3-3',
              'Column 4': '3-4',
            },
            {
              'Column 1': 4,
              'Column 2': 5,
              'Column 3': 6,
              'Column 4': 7,
            },
          ]}
        >
          Download
        </CSVDownloader>
      );
    }

    data= can be a function that returns a data object.

    <CSVDownloader
      filename={'filename'}
      data={() => {
        return [
          {
            "Column 1": "1-1",
            "Column 2": "1-2",
            "Column 3": "1-3",
            "Column 4": "1-4",
          }
        ]}
      }
    >
      Download
    </CSVDownloader>

    Install

    npm
    $ npm install react-papaparse --save

    yarn
    $ yarn add react-papaparse --save