EatSheet.xlsx
npm
A1
=PREVIEW(file, in="next.js")

Preview an XLSX file in Next.js

To preview an XLSX file in Next.js, use a client component and import EatSheet inside an effect. Next.js also runs client components on the server, so the worker must only load in the browser.

1. Install it

npm install eatsheet

2. Add app/excel-preview.jsx

'use client';

import { useEffect, useRef, useState } from 'react';
import 'eatsheet/eatsheet.css';

export function ExcelPreview({ file }) {
  const box = useRef(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const element = box.current;
    let book, gone = false, frame = 0;
    setError(null);

    const draw = async () => {
      const { html } = await book.render(0, { offset: element.scrollTop });
      if (!gone) element.innerHTML = html; // EatSheet escapes cell content
    };
    const onScroll = () => {
      cancelAnimationFrame(frame);
      frame = requestAnimationFrame(() => draw().catch(setError));
    };

    // Imported here so it only ever loads in the browser
    import('eatsheet/worker')
      .then(({ openWorkbook }) => openWorkbook(file))
      .then(opened => {
        if (gone) return opened.close();
        book = opened;
        element.addEventListener('scroll', onScroll);
        return draw();
      })
      .catch(failure => { if (!gone) setError(failure); });

    return () => {
      gone = true;
      cancelAnimationFrame(frame);
      element.removeEventListener('scroll', onScroll);
      book?.close();
    };
  }, [file]);

  return (
    <>
      {error && <p role="alert">Couldn't open this file: {error.code ?? error.message}</p>}
      <div ref={box} tabIndex={0} hidden={!!error} style={{ height: 480, overflow: 'auto' }} />
    </>
  );
}

3. Use it in app/page.jsx

'use client';

import { useState } from 'react';
import { ExcelPreview } from './excel-preview';

export default function Page() {
  const [file, setFile] = useState(null);
  return (
    <>
      <input type="file" accept=".xlsx,.csv,.tsv" onChange={e => setFile(e.target.files[0])} />
      {file && <ExcelPreview file={file} />}
    </>
  );
}
Tested on November 7, 2026 with EatSheet 0.2.3 and Next.js 16 and the App Router, using next dev and next build: a valid file, a corrupt file, then a valid file again.