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

Preview an XLSX file in Svelte

To preview an XLSX file in Svelte, open it with EatSheet in an $effect and put the returned HTML in a scrolling element. Parsing runs in a Web Worker, and only the rows in view are rendered.

1. Install it

npm install eatsheet

2. Add ExcelPreview.svelte

<script>
  import { openWorkbook } from 'eatsheet/worker';
  import 'eatsheet/eatsheet.css';

  let { file } = $props();
  let element = $state();
  let error = $state(null);

  $effect(() => {
    if (!file || !element) return;

    const box = element;
    let book, gone = false, frame = 0;
    error = null;

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

    openWorkbook(file).then(opened => {
      if (gone) return opened.close();
      book = opened;
      box.addEventListener('scroll', onScroll);
      return draw();
    }).catch(failure => { if (!gone) error = failure; });

    return () => {
      gone = true;
      cancelAnimationFrame(frame);
      box.removeEventListener('scroll', onScroll);
      book?.close();
    };
  });
</script>

{#if error}
  <p role="alert">Couldn't open this file: {error.code ?? error.message}</p>
{/if}
<div bind:this={element} tabindex="0" hidden={!!error} style="height: 480px; overflow: auto"></div>

3. Use it with a file input

<script>
  import ExcelPreview from './ExcelPreview.svelte';

  let file = $state(null);
</script>

<input type="file" accept=".xlsx,.csv,.tsv" onchange={e => (file = e.target.files[0])}>
{#if file}<ExcelPreview {file} />{/if}
For SvelteKit, only render this component in the browser, because the worker can't load on the server. We haven't tested SvelteKit separately.
Tested on November 7, 2026 with EatSheet 0.2.3 and Svelte 5.57 and Vite 8, in development and production: a valid file, a corrupt file, then a valid file again.