npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

svelte-webflow-cms

v0.0.30

Published

A config-driven CMS table editor for managing Webflow collections with SvelteKit

Readme

svelte-webflow-cms

A config-driven CMS table editor for managing Webflow collections with SvelteKit.

Features

  • Config-driven: Define your table structure with a simple configuration object
  • Change Tracking: Tracks all modifications and only enables save when changes exist
  • Batched Operations: Nothing is sent to Webflow until explicit "Save changes" click
  • Drag & Drop Sorting: Reorder items with automatic sort field updates
  • Image Handling: Client-side compression/cropping with pluggable storage backends
  • Hosting Agnostic: Works with any hosting platform (Cloudflare, Vercel, Netlify, etc.)
  • Field Validation: Required fields, length constraints, and numeric ranges with error feedback

Installation

bun add svelte-webflow-cms
# or
npm install svelte-webflow-cms

Requirements

  • SvelteKit 2.x
  • Svelte 5.x
  • Tailwind CSS v4
  • bits-ui ^2.0.0

Tailwind CSS Configuration

This library uses Tailwind CSS classes for styling. You must configure Tailwind to scan this package's files so the necessary CSS is generated.

Tailwind v4

Add a @source directive in your CSS file:

@import "tailwindcss";
@source "../node_modules/svelte-webflow-cms";

Quick Start

1. Create a config file

// src/routes/members/config.ts
import type { TableConfig } from "svelte-webflow-cms";

export const config: TableConfig = {
  pageTitle: "Team Members",
  itemSingular: "Member",
  itemPlural: "Members",
  siteId: "your-site-id",
  collectionId: "your-collection-id",
  createDeleteEnabled: true,
  draftEnabled: true,
  fields: [
    {
      visible: true,
      editable: true,
      required: true,
      schema: {
        name: "Name",
        slug: "name",
        type: "PlainText",
        validations: { maxLength: 100 },
      },
    },
    {
      visible: true,
      editable: true,
      schema: {
        name: "Photo",
        slug: "photo",
        type: "Image",
        imageSettings: { width: 400, height: 400 },
      },
    },
  ],
};

2. Set up page server

// src/routes/members/+page.server.ts
import { createCmsActions, loadCmsItems } from "svelte-webflow-cms/server";
import { createR2UploadProvider } from "svelte-webflow-cms/providers/r2";
import { config } from "./config";

export async function load({ platform }) {
  const token = platform?.env?.WEBFLOW_TOKEN;
  if (!token) return { items: [], error: "Token not found" };

  const { items, error } = await loadCmsItems(token, config);
  return { items, error };
}

export const actions = createCmsActions(config, {
  getToken: (_, platform) => platform?.env?.WEBFLOW_TOKEN ?? null,
  getUploadProvider: (_, platform) =>
    platform?.env?.TEMP_IMAGES
      ? createR2UploadProvider(
          platform.env.TEMP_IMAGES,
          "https://cdn.example.com"
        )
      : null,
  bucketPrefix: "members",
});

3. Create page component

<!-- src/routes/members/+page.svelte -->
<script lang="ts">
  import { CmsTable } from 'svelte-webflow-cms';
  import { config } from './config';

  let { data } = $props();
</script>

<CmsTable.Root {config} data={data.items}>
  <CmsTable.Toolbar />
  <CmsTable.SaveBar />
  <CmsTable.Table>
    <CmsTable.Header />
    <CmsTable.Body />
  </CmsTable.Table>
</CmsTable.Root>

Composable API

The CmsTable components follow a composable pattern (similar to shadcn-svelte), allowing you to customize and extend the table easily.

Basic Usage

<script>
  import { CmsTable } from 'svelte-webflow-cms';
</script>

<CmsTable.Root {config} data={data.items} referenceData={data.referenceData}>
  <CmsTable.Toolbar />
  <CmsTable.SaveBar />
  <CmsTable.Table>
    <CmsTable.Header />
    <CmsTable.Body />
  </CmsTable.Table>
</CmsTable.Root>

Available Components

| Component | Description | | ------------------ | ---------------------------------------------- | | CmsTable.Root | Root wrapper - provides context and state | | CmsTable.Toolbar | Title and add button | | CmsTable.SaveBar | Save/cancel controls with validation display | | CmsTable.Table | Table container | | CmsTable.Header | Table header row with field names | | CmsTable.Body | Table body with drag-and-drop support | | CmsTable.Row | Individual row (used in custom row templates) | | CmsTable.Actions | Actions column (live toggle and delete button) | | CmsTable.Cell | Field cell with input (used in custom rows) |

Customization Examples

Custom Toolbar with Badge

<CmsTable.Root {config} data={data.items}>
  <CmsTable.Toolbar>
    {#snippet afterTitle()}
      <Badge variant="secondary">{data.items.length} items</Badge>
    {/snippet}
  </CmsTable.Toolbar>
  <CmsTable.SaveBar />
  <CmsTable.Table>
    <CmsTable.Header />
    <CmsTable.Body />
  </CmsTable.Table>
</CmsTable.Root>

Custom Actions Placement

<CmsTable.Root {config} data={data.items}>
  <div class="flex items-center justify-between">
    <CmsTable.Toolbar showAddButton={false} />
    <div class="flex gap-2">
      <Button onclick={handleExport}>Export</Button>
      <CmsTable.SaveBar />
    </div>
  </div>
  <CmsTable.Table>
    <CmsTable.Header />
    <CmsTable.Body />
  </CmsTable.Table>
</CmsTable.Root>

Custom Column in Header

<CmsTable.Table>
  <CmsTable.Header>
    {#snippet afterColumns()}
      <Table.Head>Custom Column</Table.Head>
    {/snippet}
  </CmsTable.Header>
  <CmsTable.Body />
</CmsTable.Table>

Custom Row Template

<CmsTable.Body>
  {#snippet row({ item, index, isNew })}
    <CmsTable.Row {item} {index} {isNew}>
      {#snippet afterColumns()}
        <Table.Cell>
          <Badge>{item.status}</Badge>
        </Table.Cell>
      {/snippet}
    </CmsTable.Row>
  {/snippet}
</CmsTable.Body>

Styling with Classes

All components accept a class prop for custom styling:

<CmsTable.Root {config} data={data.items} class="max-w-7xl mx-auto">
  <CmsTable.Toolbar class="bg-gray-50 p-4 rounded-t-lg" />
  <CmsTable.SaveBar class="justify-start px-4" />
  <CmsTable.Table class="border-2 shadow-lg">
    <CmsTable.Header class="bg-blue-50" />
    <CmsTable.Body class="text-sm" />
  </CmsTable.Table>
</CmsTable.Root>

Upload Providers

The library supports pluggable storage backends. Implement the UploadProvider interface for your storage:

interface UploadProvider {
  upload(
    file: Blob,
    filename: string,
    contentType: string
  ): Promise<{ url: string; filename: string }>;
  delete(filename: string): Promise<void>;
}

Built-in: Cloudflare R2

import { createR2UploadProvider } from "svelte-webflow-cms/providers/r2";

getUploadProvider: (_, platform) =>
  createR2UploadProvider(platform.env.BUCKET, "https://cdn.example.com");

Custom Provider Example (S3)

export function createS3UploadProvider(
  client,
  bucket,
  baseUrl
): UploadProvider {
  return {
    async upload(file, filename, contentType) {
      await client.send(
        new PutObjectCommand({
          Bucket: bucket,
          Key: filename,
          Body: Buffer.from(await file.arrayBuffer()),
          ContentType: contentType,
        })
      );
      return { url: `${baseUrl}/${filename}`, filename };
    },
    async delete(filename) {
      await client.send(
        new DeleteObjectCommand({ Bucket: bucket, Key: filename })
      );
    },
  };
}

Token Configuration

The getToken function receives the request and platform at runtime:

// Cloudflare Pages
getToken: (_, platform) => platform?.env?.WEBFLOW_TOKEN ?? null;

// Node.js
getToken: () => process.env.WEBFLOW_TOKEN ?? null;

// SvelteKit $env
import { env } from "$env/dynamic/private";
getToken: () => env.WEBFLOW_TOKEN ?? null;

Supported Field Types

| Type | Input Component | Notes | | ---------------- | ------------------- | --------------------------------------- | | PlainText | TextInput | Supports maxLength/minLength validation | | RichText | TextInput | Supports maxLength/minLength validation | | Link | LinkInput | URL input | | Email | EmailInput | Email input | | Phone | PhoneInput | Phone input | | Number | NumberInput | Numeric input with range validation | | Switch | SwitchInput | Boolean toggle | | Option | OptionInput | Dropdown select | | Color | ColorInput | Color picker | | DateTime | DateInput | Calendar picker with date selection | | Image | ImageInput | Image upload with processing | | Reference | ReferenceInput | Single collection reference | | MultiReference | MultiReferenceInput | Multiple collection refs |

Field Configuration Options

Field

interface Field {
  visible: boolean; // Show in table
  editable?: boolean; // Allow editing
  required?: boolean; // Field is required
  styles?: FieldStyles; // Custom styling
  schema: FieldSchema; // Field schema
}

Field Validations

interface Validations {
  minLength?: number; // Minimum string length
  maxLength?: number; // Maximum string length
  min?: number; // Minimum numeric value
  max?: number; // Maximum numeric value
}

Sort Field

Sort fields now support DateTime type in addition to Number:

interface SortField extends Field {
  direction?: "asc" | "desc"; // Sort direction
  schema: SortFieldSchema;
}

interface SortFieldSchema extends FieldSchema {
  type: "Number" | "DateTime"; // Number or DateTime
}

API Reference

Components

CmsTable Components:

  • CmsTable.Root - Root wrapper that provides context and state management
  • CmsTable.Toolbar - Title and add button with customizable slots
  • CmsTable.SaveBar - Save/cancel controls with validation error display
  • CmsTable.Table - Table container with styling
  • CmsTable.Header - Table header row with field names and tooltips
  • CmsTable.Body - Table body with drag-and-drop support
  • CmsTable.Row - Individual row component (for custom row templates)
  • CmsTable.Actions - Actions column with live toggle and delete button
  • CmsTable.Cell - Field cell with appropriate input component

Input Components (can be used independently):

  • TextInput - Plain text and rich text input
  • NumberInput - Numeric input with validation
  • LinkInput - URL input
  • EmailInput - Email input
  • PhoneInput - Phone input
  • ColorInput - Color picker
  • SwitchInput - Boolean toggle
  • OptionInput - Dropdown select
  • DateInput - Calendar date picker
  • ImageInput - Image upload with compression
  • ReferenceInput - Single collection reference selector
  • MultiReferenceInput - Multiple collection reference selector

Server Functions

  • createCmsActions(config, options) - Create all CMS actions
  • loadCmsItems(token, config) - Load items from Webflow
  • loadReferenceData(token, config) - Load referenced collection data
  • createWebflowClient(token) - Create Webflow API client

Types

  • TableConfig - Table configuration
  • Field - Field configuration
  • UploadProvider - Upload provider interface
  • UploadProviderFactory - Factory for creating providers
  • TokenGetter - Token retrieval function type

License

MIT