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-reorderable-list

v1.0.5

Published

A simple and accessible reorderable list component for Svelte 5.

Downloads

96

Readme

Svelte Reorderable List

A simple and accessible reorderable list component for Svelte 5.

Features

  • Drag and drop to reorder items.
  • Touch support for mobile devices.
  • Accessibility support: keyboard navigation with Ctrl + Arrow keys.
  • Horizontal and vertical lists.
  • Customizable drag handle.
  • Built with Svelte 5 runes.

Installation

pnpm install svelte-reorderable-list

Demo

Basic List Reordering

Simple List Demo

Horizontal Layout

Horizontal Layout Demo

Custom Drag Handle

Drag Handle Demo

Keyboard Navigation

Use Tab key to focus element and then Ctrl+Arrows to move.

Vertical Lists:

Keyboard Vertical Demo

Horizontal Lists:

Keyboard Horizontal Demo

Usage

Here is a basic example of how to use the ReorderableList component.

<script>
    import ReorderableList from 'svelte-reorderable-list';


    let items = [
        { id: '1', text: 'Item 1' },
        { id: '2', text: 'Item 2' },
        { id: '3', text: 'Item 3' },
        { id: '4', text: 'Item 4' },
    ];
    // or items = $state([...])

    const getKey = (item) => item.id;

    function handleUpdate(updatedItems) {
        items = updatedItems;
    }
</script>

{#snippet item(item, index)}
    <div class="item">
        <span>{item.text}</span>
    </div>
{/snippet}

<ReorderableList
    items={items}
    getKey={getKey}
    onUpdate={handleUpdate}
    item={item}
/>

<style>
    .item {
        padding: 1rem;
        border: 1px solid #ccc;
        background-color: #f9f9f9;
    }
</style>

Props

| Prop | Type | Required | Default | Description | | ------------------- | ------------------------------------------ | -------- | ----------- | ------------------------------------------------------------------------------------------------------- | | items | ItemType[] | Yes | undefined | The array of items to be displayed. | | getKey | (item: ItemType) => string | Yes | undefined | A function that returns a unique key for each item. | | item | Snippet<[ItemType, number]> | Yes | undefined | A Svelte 5 snippet for rendering each item. It receives the item and its index. | | onUpdate | (items: ItemType[]) => void | Yes | undefined | Callback function that is called with the new item order after a change. | | direction | "horizontal" \| "vertical" | No | "vertical" | The direction of the list. | | disabled | boolean | No | false | When true, the reordering functionality is disabled. | | cssSelectorHandle | string | No | undefined | A CSS selector for the drag handle. If not provided, the entire item is draggable. |

Theming and Customization

The components use CSS custom properties for theming. You can customize the appearance by overriding these variables in your CSS:

:root {
    /* Focus and interaction colors */
    --reorderable-focus-color: #007acc;
    --reorderable-focus-offset: 2px;
    --reorderable-focus-radius: 3px;
    
    /* Drag clone appearance */
    --reorderable-drag-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
    --reorderable-drag-opacity: 0.6;
    --reorderable-drag-scale: 1.02;
    
    /* Keyboard tip styling */
    --reorderable-keyboard-tip-bg: #016DB6;
    --reorderable-keyboard-tip-color: white;
    --reorderable-keyboard-tip-radius: 4px;
    
    /* Drop indicators (for tree component) */
    --reorderable-drop-indicator-color: #007acc;
    --reorderable-drop-indicator-radius: 2px;
    --reorderable-drop-child-bg: rgba(0, 122, 204, 0.2);
}

Example: Dark Theme

:root {
    --reorderable-focus-color: #4fc3f7;
    --reorderable-keyboard-tip-bg: #2196f3;
    --reorderable-drop-indicator-color: #4fc3f7;
    --reorderable-drag-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}

Example: Custom Brand Colors

:root {
    --reorderable-focus-color: #6366f1;
    --reorderable-keyboard-tip-bg: #4f46e5;
    --reorderable-drop-indicator-color: #6366f1;
    --reorderable-drop-child-bg: rgba(99, 102, 241, 0.1);
}

Tree Component

Tree Demo

Tree Demo

Tree Keyboard Navigation

Use Tab key to focus element and then Ctrl+Arrows to move.

Tree Keyboard Demo

The library also includes a ReorderableTree component for hierarchical data. It supports two input modes:

Tree Mode (Hierarchical Structure)

<script>
    import { ReorderableTree, type TreeNode } from 'svelte-reorderable-list';

    let treeNodes: TreeNode<{ id: string; name: string; }>[] = [
        {
            item: { id: '1', name: 'Parent 1' },
            children: [
                { item: { id: '1-1', name: 'Child 1.1' } },
                { item: { id: '1-2', name: 'Child 1.2' } }
            ]
        },
        {
            item: { id: '2', name: 'Parent 2' },
            children: [
                { item: { id: '2-1', name: 'Child 2.1' } }
            ]
        }
    ];

    const getKey = (item) => item.id;

    function handleTreeUpdate(updatedNodes) {
        treeNodes = updatedNodes;
    }
</script>

{#snippet item(item, index)}
    <div class="tree-item">
        <span>{item.name}</span>
    </div>
{/snippet}

<ReorderableTree
    treeNodes={treeNodes}
    getKey={getKey}
    onUpdate={handleTreeUpdate}
    item={item}
    levelPadding="20px"
/>

Flat Mode (Parent-Child References)

For easier data management, you can also use a flat structure where hierarchy is defined by parentKey references. If a node's parentKey does not match any existing key, the library logs a console.error and skips rendering that item:

<script>
    import { ReorderableTree, type FlatTreeNode } from 'svelte-reorderable-list';

    let flatNodes: FlatTreeNode<{ id: string; name: string; }>[] = [
        { item: { id: '1', name: 'Parent 1' }, key: '1' },
        { item: { id: '1-1', name: 'Child 1.1' }, key: '1-1', parentKey: '1' },
        { item: { id: '1-2', name: 'Child 1.2' }, key: '1-2', parentKey: '1' },
        { item: { id: '2', name: 'Parent 2' }, key: '2' },
        { item: { id: '2-1', name: 'Child 2.1' }, key: '2-1', parentKey: '2' }
    ];

    function handleFlatTreeUpdate(updatedNodes) {
        flatNodes = updatedNodes;
    }
</script>

{#snippet item(item, index)}
    <div class="tree-item">
        <span>{item.name}</span>
    </div>
{/snippet}

<ReorderableTree
    flatNodes={flatNodes}
    onUpdate={handleFlatTreeUpdate}
    item={item}
    levelPadding="20px"
/>

Tree Component Props

The ReorderableTree component automatically detects the input mode based on the props provided.

Tree Mode Props

| Prop | Type | Required | Default | Description | | ------------------- | ------------------------------------------ | -------- | ----------- | ------------------------------------------------------------------------------------------------------- | | treeNodes | TreeNode<ItemType>[] | Yes | undefined | The array of tree nodes to be displayed. | | getKey | (item: ItemType) => string | Yes | undefined | A function that returns a unique key for each item. | | onUpdate | (nodes: TreeNode<ItemType>[]) => void | Yes | undefined | Callback function that is called with the new tree structure after a change. |

Flat Mode Props

| Prop | Type | Required | Default | Description | | ------------------- | ----------------------------------------------- | -------- | ----------- | ------------------------------------------------------------------------------------------------------- | | flatNodes | FlatTreeNode<ItemType>[] | Yes | undefined | The array of flat tree nodes with parentKey references. | | onUpdate | (flatNodes: FlatTreeNode<ItemType>[]) => void | Yes | undefined | Callback function that is called with the new flat structure after a change. |

Common Props

| Prop | Type | Required | Default | Description | | ------------------- | ------------------------------------------ | -------- | ----------- | ------------------------------------------------------------------------------------------------------- | | item | Snippet<[ItemType, number]> | Yes | undefined | A Svelte 5 snippet for rendering each item. It receives the item and its index. | | disabled | boolean | No | false | When true, the reordering functionality is disabled. | | cssSelectorHandle | string | No | undefined | A CSS selector for the drag handle. If not provided, the entire item is draggable. | | levelPadding | string | No | "20px" | CSS padding value for each nesting level. |

Type Definitions

interface TreeNode<ItemType> {
    item: ItemType;
    children?: TreeNode<ItemType>[];
}

interface FlatTreeNode<ItemType> {
    item: ItemType;
    key: string;
    parentKey?: string;
}

Choosing Between Tree and Flat Mode

Use Tree Mode When:

  • Your data is naturally hierarchical (e.g., file systems, nested categories)
  • You prefer working with nested object structures
  • You need to maintain the tree structure in your existing data model

Use Flat Mode When:

  • Your data comes from a database with parent-child relationships
  • You need easier state management and updates
  • You want to avoid deep nesting complexity
  • You're working with dynamic hierarchies that change frequently

Both modes provide identical functionality and user experience - the choice is purely about data structure preference.

Tree Keyboard Navigation

  • Use Tab to focus on an item.
  • Ctrl + ↑/↓: Move item up/down within the same level
  • Ctrl + ←: Move item up one level (make it sibling of its parent)
  • Ctrl + →: Make item a child of the previous item

Accessibility

General Accessibility Features

  • Full keyboard navigation support
  • ARIA attributes for screen readers
  • Focus management with visible focus indicators
  • Reduced motion support for users with vestibular disorders
  • High contrast mode support

Keyboard Navigation

List Component

  • Use Tab to focus on an item.
  • Once an item is focused, use Ctrl + ArrowUp/ArrowDown for vertical lists or Ctrl + ArrowLeft/ArrowRight for horizontal lists to move the item.

Tree Component

  • Use Tab to focus on an item.
  • Once an item is focused, use the keyboard shortcuts described above for tree navigation.