Export to SPSS

Export to SPSS (.sav)

The SPSS extension converts a Jspreadsheet or raw JSON dataset into an SPSS system file (.sav), which can be opened directly in SPSS, PSPP, or any tool that reads the PSPP System File Format. Column types, formatting, value labels, variable labels, display width, alignment and measure levels are automatically converted according to the spreadsheet configuration.

Supports client-side and Node.js platforms
This extension writes to a pure binary Uint8Array, so it can be used to download files in a browser or persist files to disk from a backend script.

Documentation

Available settings

Property Description
filename: string The filename used by the download assistant. Default: data.sav
fileLabel: string Optional file label (maximum 64 characters) embedded in the .sav header. If not specified, it falls back to worksheetName.
headers: string[] Column headers when passing a raw array of data instead of a worksheet instance.
columns: object[] Column definitions (type, format, source, width, etc.) used when passing a raw array of data.
comments: object | array Cell comments to retain in the .sav document record. Can be an array of { cell, comment } or a mapping of { "A1": "text" }.

Type mapping

This extension maps each column type to the corresponding SPSS variable definition:

Jspreadsheet column type SPSS variable Measure Description
number, numeric, autonumber Numeric (F) Scale Width / decimal places inferred from the column format / mask
percent Numeric (PCT) Scale Decimal places inferred from the format
calendar Numeric (DATE11 / DATETIME22) Scale Converted to seconds since 1582-10-14. A time component triggers DATETIME.
rating, progressbar Numeric Ordinal
checkbox, radio Numeric (0 / 1) Nominal Value labels 0 = No, 1 = Yes automatically written
dropdown, autocomplete with { id, name } source (numeric IDs) Numeric Nominal Source written as SPSS value labels
dropdown, autocomplete (string source) String (A) Nominal Written in SPSS value-label form
text, html, email, url, tags, color, image, notes String (A) Nominal Width automatically increases according to the longest cell; long strings use continuation records

Methods

After registration, two helper methods are added to each worksheet, and the extension itself also exposes equivalent static methods:

Method Description
worksheet.downloadSav(options?) Generates a .sav file and triggers the browser to download it.
worksheet.generateSav(options?) Generates a .sav binary file and returns it as a Uint8Array.
spss.download(worksheet, options?) Static version of downloadSav.
spss.generate(worksheet, options?) Static version of generateSav. Also accepts a raw data[][] array.

Installation

Choose one of the following options:

Using NPM

$ npm install @jspreadsheet/spss

Using a CDN

<script src="https://cdn.jsdelivr.net/npm/@jspreadsheet/spss/dist/index.js"></script>

SPSS limitations

When exporting to .sav, be aware of the fixed constraints imposed by the SPSS System File Format. The extension handles these transparently, but some values may be coerced:

  • Allowed characters: Variable names only accept A-Z, a-z, 0-9, @, #, $, _ and .. Invalid characters are replaced with _.
  • String width: SPSS stores strings as 8-byte segments. Strings longer than 255 characters are written using continuation records.
  • Value labels: Each label is limited to 120 bytes. Numeric value labels are only emitted when the data source uses { id, name } pairs with numeric IDs.
  • Dates: Calendar columns are stored as SPSS numeric date values (seconds since October 14, 1582). When the column format contains a time component (H / h), the DATETIME22 format is used; otherwise, DATE11.
  • Missing values: Empty cells are converted to the SPSS system-missing value (SYSMIS).
  • Encoding: The file is written in UTF-8 (character code 65001).

Code examples

Creating a .sav file using JavaScript

How to export a spreadsheet to an SPSS .sav file.

<html>
<script src="https://jspreadsheet.com/v12/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v12/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://jsuites.net/v6/jsuites.css" type="text/css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />

<script src="https://cdn.jsdelivr.net/npm/@jspreadsheet/spss/dist/index.js"></script>

<div id='spreadsheet'></div>

<p><input type="button" value="Download .sav" id="btn1" /></p>

<script>
// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// This license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate an extended demo license.
jspreadsheet.setLicense('NDI4OWE2ZDNjMDBjYjBjNGYwZWYyYTc5OWNiMDY0MmU1ZTgxZWNjNzZlNjY3YjIyMTE2MmQwN2NlN2NmMTJlMmUwNDlhMTU1ZTczOTA3OTk0ZGM1NzBkZDI4NmEyZDRiZGNhZjExNDI1MTkwOTNkNWM1MmIyYzM3ODhiMjMwZjMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpjM01EQXhPVGszTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

// Spreadsheet plugin
jspreadsheet.setExtensions({ spss });

// Create a spreadsheet
let worksheets = jspreadsheet(document.getElementById('spreadsheet'), {
    worksheets: [{
        worksheetName: 'Survey',
        columns: [
            { type: 'text', title: 'Name', width: 160 },
            { type: 'number', title: 'Age', format: '0' },
            { type: 'dropdown', title: 'Gender', source: [
                { id: 1, name: 'Female' },
                { id: 2, name: 'Male' },
                { id: 3, name: 'Other' },
            ]},
            { type: 'calendar', title: 'Date of Birth', format: 'DD/MM/YYYY' },
            { type: 'checkbox', title: 'Subscribed' },
        ],
        data: [
            ['Alice', 34, 1, '1990-04-12', true],
            ['Bob',   27, 2, '1997-11-02', false],
            ['Carol', 41, 1, '1983-06-20', true],
        ],
    }],
});

document.getElementById("btn1").onclick = function() {
    worksheets[0].downloadSav({ filename: 'survey.sav' });
}
</script>
</html>
import React, { useRef } from "react";
import { Spreadsheet, Worksheet } from "@jspreadsheet/react";
import jspreadsheet from "jspreadsheet";
import spss from "@jspreadsheet/spss";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// This license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with a longer validity period.
jspreadsheet.setLicense('NDI4OWE2ZDNjMDBjYjBjNGYwZWYyYTc5OWNiMDY0MmU1ZTgxZWNjNzZlNjY3YjIyMTE2MmQwN2NlN2NmMTJlMmUwNDlhMTU1ZTczOTA3OTk0ZGM1NzBkZDI4NmEyZDRiZGNhZjExNDI1MTkwOTNkNWM1MmIyYzM3ODhiMjMwZjMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpjM01EQXhPVGszTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

// JSS data grid plugin
jspreadsheet.setExtensions({ spss });

export default function App() {
    // Spreadsheet worksheet array
    const spreadsheet = useRef();

    const download = function() {
        spreadsheet.current[0].downloadSav({ filename: 'survey.sav' });
    }

    // Rendering component
    return (
        <>
            <Spreadsheet ref={spreadsheet}>
                <Worksheet minDimensions={[6, 6]} />
            </Spreadsheet>
            <input type="button" value="Download .sav" onClick={() => download()} />
        </>
    );
}
<template>
    <Spreadsheet ref="spreadsheet" :license="license" :extensions="extensions">
        <Worksheet :minDimensions="[10,10]" />
    </Spreadsheet>
    <input type="button" value="Download .sav" @click="download" />
</template>

<script>
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/vue";
import spss from "@jspreadsheet/spss";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// Define the data grid license
const license = 'NDI4OWE2ZDNjMDBjYjBjNGYwZWYyYTc5OWNiMDY0MmU1ZTgxZWNjNzZlNjY3YjIyMTE2MmQwN2NlN2NmMTJlMmUwNDlhMTU1ZTczOTA3OTk0ZGM1NzBkZDI4NmEyZDRiZGNhZjExNDI1MTkwOTNkNWM1MmIyYzM3ODhiMjMwZjMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpjM01EQXhPVGszTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9';

// Define the data grid extensions
const extensions = { spss };

export default {
    components: {
        Spreadsheet,
        Worksheet,
    },
    methods: {
        download() {
            // Worksheet instance
            this.$refs.spreadsheet.current[0].downloadSav({ filename: 'survey.sav' });
        }
    },
    data() {
        return {
            license,
            extensions,
        };
    }
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
import spss from "@jspreadsheet/spss";

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// This license is valid for one day, after which the spreadsheet will become read-only.
jspreadsheet.setLicense('NDI4OWE2ZDNjMDBjYjBjNGYwZWYyYTc5OWNiMDY0MmU1ZTgxZWNjNzZlNjY3YjIyMTE2MmQwN2NlN2NmMTJlMmUwNDlhMTU1ZTczOTA3OTk0ZGM1NzBkZDI4NmEyZDRiZGNhZjExNDI1MTkwOTNkNWM1MmIyYzM3ODhiMjMwZjMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpjM01EQXhPVGszTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

// Extend
jspreadsheet.setExtensions({ spss });

@Component({
    standalone: true,
    selector: "app-root",
    template: `<div #spreadsheet></div>
    <input type="button" value="Download .sav" (click)="this.export()" />`
})
export class AppComponent {
    @ViewChild("spreadsheet") spreadsheet: ElementRef;
    // Worksheets
    worksheets: jspreadsheet.worksheetInstance[];
    // Create a new data grid
    ngAfterViewInit() {
        // Create a spreadsheet
        this.worksheets = jspreadsheet(this.spreadsheet.nativeElement, {
            worksheets: [
                { minDimensions: [6, 6] }
            ]
        });
    }
    export() {
        // Worksheet instance
        this.worksheets[0].downloadSav({ filename: 'survey.sav' });
    }
}

Backend .sav export

This extension also works in Node.js — generate returns a raw Uint8Array that you can persist directly to disk without rendering the DOM.

const jspreadsheet = require('jspreadsheet');
const spss = require('@jspreadsheet/spss');
const { writeFile } = require('node:fs/promises');

jspreadsheet.setLicense({
    clientId: '356a192b7913b04c54574d18c28d46e6395428ab',
    licenseKey: 'NDI4OWE2ZDNjMDBjYjBjNGYwZWYyYTc5OWNiMDY0MmU1ZTgxZWNjNzZlNjY3YjIyMTE2MmQwN2NlN2NmMTJlMmUwNDlhMTU1ZTczOTA3OTk0ZGM1NzBkZDI4NmEyZDRiZGNhZjExNDI1MTkwOTNkNWM1MmIyYzM3ODhiMjMwZjMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpjM01EQXhPVGszTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9'
});

jspreadsheet.setExtensions({ spss });

let spreadsheet = jspreadsheet(null, {
    worksheets: [{
        worksheetName: 'Survey',
        columns: [
            { type: 'text', title: 'Name' },
            { type: 'number', title: 'Age', format: '0' },
            { type: 'calendar', title: 'Date of Birth', format: 'DD/MM/YYYY' },
        ],
        data: [
            ['Alice', 34, '1990-04-12'],
            ['Bob',   27, '1997-11-02'],
        ],
    }],
});

const binary = spreadsheet[0].generateSav({ fileLabel: 'Survey' });
await writeFile('survey.sav', binary);

The spss.generate function also accepts raw arrays of data and columns, so you can generate SPSS files without instantiating a spreadsheet.

const spss = require('@jspreadsheet/spss');
const { writeFile } = require('node:fs/promises');

const binary = spss.generate([
    ['Alice', 34, 1],
    ['Bob',   27, 2],
    ['Carol', 41, 1],
], {
    headers: ['Name', 'Age', 'Gender'],
    columns: [
        { type: 'text', name: 'Name' },
        { type: 'number', name: 'Age', format: '0' },
        { type: 'dropdown', name: 'Gender', source: [
            { id: 1, name: 'Female' },
            { id: 2, name: 'Male' },
        ]},
    ],
    fileLabel: 'Survey',
});

await writeFile('survey.sav', binary);

Examples

Integration with React

React spreadsheet working example.