A highly customizable and interactive spreadsheet component for Svelte, built with Svelte 5 Runes. Inspired by Excel and Google Sheets, it's designed to handle complex data interactions with ease.
text, number, date, select, and function cell types.select dropdowns from an API.Install the package using npm (or your preferred package manager):
npm install @sciefylab/svelte-spreadsheet
Hereβs a comprehensive example demonstrating how to implement the Svelte-Spreadsheet component.
First, import the Spreadsheet component into your Svelte file.
<script>
// Make sure the import path matches your project structure
import Spreadsheet from '@sciefylab/svelte-spreadsheet';
</script>
Define your column structure, initial data, and render the component. Use the bind:this directive to get a reference to the component instance. This allows you to call its public methods, like getAllData().
<script>
import Spreadsheet from '@sciefylab/svelte-spreadsheet';
let spreadsheetComponent; // Variable to hold the component instance
const columns = [
{
key: "name",
label: "Name",
type: "select",
width: "150px",
// Fetch options from an external API
fetchOptions: async (query) => {
try { // Corrected URL string
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await response.json();
const options = users.map(user => ({ value: String(user.id), label: user.name }));
// Filter results based on user input
return options.filter(opt => opt.label.toLowerCase().includes(query.toLowerCase()));
} catch (error) {
console.error("Failed to fetch users:", error);
return [];
}
},
},
{
key: "age",
label: "Age",
type: "number",
width: "100px",
},
{
key: "birthdate",
label: "Birthdate",
type: "date",
width: "150px",
},
{
key: "country",
label: "Country",
type: "select",
width: "120px",
options: [
{ value: "us", label: "United States" },
{ value: "ca", label: "Canada" },
{ value: "mx", label: "Mexico" },
],
// Handle changes to update other cells; all parameters (selectedOption, currentCell, fullRowData, allColumns) are available
onChange: (selectedOption) => {
if (selectedOption.value === "us") {
return [{ targetColumnKey: "city", value: { value: "ny", label: "New York" } }];
} else {
return [{ targetColumnKey: "city", value: "" }]; // Clear city if country changes
}
}
},
{
key: "city",
label: "City",
type: "select",
width: "120px",
readonly: true, // This column is now controlled by the 'country' column
fetchParamsFromColumns: ["country"], // Depends on the 'country' column
async fetchOptions(query, params) {
const countryValue = params.country;
let cities = [];
// Simulate fetching city data based on the selected country
if (countryValue === "us") {
cities = [{ value: "ny", label: "New York" }, { value: "la", label: "Los Angeles" }];
} else if (countryValue === "ca") {
cities = [{ value: "to", label: "Toronto" }, { value: "va", label: "Vancouver" }];
} else if (countryValue === "mx") {
cities = [{ value: "mc", label: "Mexico City" }, { value: "gua", label: "Guadalajara" }];
}
return cities.filter(city => city.label.toLowerCase().includes(query.toLowerCase()));
}
},
{
key: "age_next_year",
label: "Age Next Year",
type: "function",
// Calculate value based on other cells in the same row
function: (rowData) => (rowData.age != null) ? rowData.age + 1 : ""
}
];
const initialData = [
{
name: { value: "1", label: "Leanne Graham" },
age: 30,
country: { value: "us", label: "United States" },
city: { value: "ny", label: "New York" },
birthdate: "1995-05-15",
},
{
name: { value: "2", label: "Ervin Howell" },
age: 25,
country: { value: "ca", label: "Canada" },
city: { value: "to", label: "Toronto" },
birthdate: "2000-08-22",
},
];
// Function to get all data from the spreadsheet instance
function handleGetAllData() {
if (spreadsheetComponent) {
const allData = spreadsheetComponent.getAllData();
console.log("All data from the worksheet:", allData);
alert("Data has been logged to the console. Press F12 to view.");
}
}
</script>
<!-- Button to trigger data retrieval -->
<button on:click={handleGetAllData} class="my-4 p-2 bg-blue-500 text-white rounded">
Get All Spreadsheet Data
</button>
<!-- Render the spreadsheet -->
<Spreadsheet
bind:this={spreadsheetComponent}
{columns}
{initialData}
/>
| Prop | Type | Description |
|---|---|---|
columns |
Array<Object> |
Required. An array of objects defining the structure and behavior of each column. |
initialData |
Array<Object> |
An array of objects representing the initial rows of data. This is the primary way to provide data. |
initialWorksheets |
Array<Object> |
Alternative to initialData. Expects [{ name: string, grid: Array<Array<{value: any}>> }], where grid is pre-formatted. If initialData is present, it takes precedence. Currently, only the first worksheet is used. |
rowHeight |
number |
The height of each row in pixels. Defaults to 30. |
Each object in the columns prop can have the following properties:
| Key | Type | Description |
|---|---|---|
key |
string |
Required. The unique identifier for the column, corresponding to a key in the data objects. |
label |
string |
Required. The display name for the column header. |
type |
string |
The cell type. Can be 'text', 'number', 'date', 'select', 'function'. Defaults to 'text'. |
width |
string |
The CSS width of the column (e.g., '150px'). |
readonly |
boolean |
If true, the cells in this column cannot be edited. |
options |
Array |
An array of { value, label } objects for select type columns. |
fetchOptions |
async (query, params) => Array |
An async function for select type to fetch options dynamically. query is the search term. |
fetchParamsFromColumns |
Array<string> |
An array of column keys whose values will be passed as the params object to fetchOptions. |
onChange |
(selectedOption, currentCell, fullRowData, allColumnsConfig) => Array |
A callback for select type that triggers when the value changes. selectedOption is the chosen {value, label}. currentCell is the grid cell object. fullRowData is an object of the current row's data. allColumnsConfig is the full columns definition. Can return an array of updates for other cells. |
function |
(rowData) => any |
A function for function type that computes the cell's value based on the current rowData. |
You can call these methods on the component instance obtained via bind:this.
| Method | Parameters | Returns | Description |
|---|---|---|---|
getAllData() |
none |
Array<Object> |
Returns the complete and current data from all rows in the active worksheet. |
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
This project is MIT licensed.