{"id":29915663,"url":"https://github.com/lexriver/svelte-reorderable-list","last_synced_at":"2026-01-20T17:38:26.060Z","repository":{"id":303835902,"uuid":"1016276051","full_name":"LexRiver/svelte-reorderable-list","owner":"LexRiver","description":"reorder list by dragging items or by keyboard","archived":false,"fork":false,"pushed_at":"2025-07-16T11:15:41.000Z","size":4013,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-17T15:07:30.783Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Svelte","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LexRiver.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-08T18:54:47.000Z","updated_at":"2025-07-16T11:15:44.000Z","dependencies_parsed_at":"2025-07-10T01:11:39.722Z","dependency_job_id":"ee165fdc-643f-409c-860a-620bf50af222","html_url":"https://github.com/LexRiver/svelte-reorderable-list","commit_stats":null,"previous_names":["lexriver/svelte-reorderable-list"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LexRiver/svelte-reorderable-list","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LexRiver%2Fsvelte-reorderable-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LexRiver%2Fsvelte-reorderable-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LexRiver%2Fsvelte-reorderable-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LexRiver%2Fsvelte-reorderable-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LexRiver","download_url":"https://codeload.github.com/LexRiver/svelte-reorderable-list/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LexRiver%2Fsvelte-reorderable-list/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268330945,"owners_count":24233152,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-02T03:19:40.011Z","updated_at":"2026-01-20T17:38:26.053Z","avatar_url":"https://github.com/LexRiver.png","language":"Svelte","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Svelte Reorderable List\n\nA simple and accessible reorderable list component for Svelte 5.\n\n## Features\n\n-   Drag and drop to reorder items.\n-   Touch support for mobile devices.\n-   Accessibility support: keyboard navigation with Ctrl + Arrow keys.\n-   Horizontal and vertical lists.\n-   Customizable drag handle.\n-   Built with Svelte 5 runes.\n\n## Installation\n\n```bash\npnpm install svelte-reorderable-list\n```\n\n## Demo\n\n### Basic List Reordering\n\n![Simple List Demo](https://raw.githubusercontent.com/LexRiver/svelte-reorderable-list/main/static/img/simple-list.gif)\n\n### Horizontal Layout\n\n![Horizontal Layout Demo](https://raw.githubusercontent.com/LexRiver/svelte-reorderable-list/main/static/img/horizontal-layout.gif)\n\n### Custom Drag Handle\n\n![Drag Handle Demo](https://raw.githubusercontent.com/LexRiver/svelte-reorderable-list/main/static/img/drag-handle.gif)\n\n### Keyboard Navigation\n\nUse `Tab` key to focus element and then `Ctrl`+`Arrows` to move.\n\n**Vertical Lists:**\n\n![Keyboard Vertical Demo](https://raw.githubusercontent.com/LexRiver/svelte-reorderable-list/main/static/img/keyboard-vertical.gif)\n\n**Horizontal Lists:**\n\n![Keyboard Horizontal Demo](https://raw.githubusercontent.com/LexRiver/svelte-reorderable-list/main/static/img/keyboard-horizontal.gif)\n\n## Usage\n\nHere is a basic example of how to use the `ReorderableList` component.\n\n```svelte\n\u003cscript\u003e\n    import ReorderableList from 'svelte-reorderable-list';\n\n\n    let items = [\n        { id: '1', text: 'Item 1' },\n        { id: '2', text: 'Item 2' },\n        { id: '3', text: 'Item 3' },\n        { id: '4', text: 'Item 4' },\n    ];\n    // or items = $state([...])\n\n    const getKey = (item) =\u003e item.id;\n\n    function handleUpdate(updatedItems) {\n        items = updatedItems;\n    }\n\u003c/script\u003e\n\n{#snippet item(item, index)}\n    \u003cdiv class=\"item\"\u003e\n        \u003cspan\u003e{item.text}\u003c/span\u003e\n    \u003c/div\u003e\n{/snippet}\n\n\u003cReorderableList\n    items={items}\n    getKey={getKey}\n    onUpdate={handleUpdate}\n    item={item}\n/\u003e\n\n\u003cstyle\u003e\n    .item {\n        padding: 1rem;\n        border: 1px solid #ccc;\n        background-color: #f9f9f9;\n    }\n\u003c/style\u003e\n```\n\n## Props\n\n| Prop                | Type                                       | Required | Default     | Description                                                                                             |\n| ------------------- | ------------------------------------------ | -------- | ----------- | ------------------------------------------------------------------------------------------------------- |\n| `items`             | `ItemType[]`                               | Yes      | `undefined` | The array of items to be displayed.                                                                     |\n| `getKey`            | `(item: ItemType) =\u003e string`               | Yes      | `undefined` | A function that returns a unique key for each item.                                                     |\n| `item`              | `Snippet\u003c[ItemType, number]\u003e`              | Yes      | `undefined` | A Svelte 5 snippet for rendering each item. It receives the item and its index.                         |\n| `onUpdate`          | `(items: ItemType[]) =\u003e void`              | Yes      | `undefined` | Callback function that is called with the new item order after a change.                                |\n| `direction`         | `\"horizontal\" \\| \"vertical\"`               | No       | `\"vertical\"`  | The direction of the list.                                                                              |\n| `disabled`          | `boolean`                                  | No       | `false`     | When `true`, the reordering functionality is disabled.                                                  |\n| `cssSelectorHandle` | `string`                                   | No       | `undefined` | A CSS selector for the drag handle. If not provided, the entire item is draggable.                      |\n\n## Theming and Customization\n\nThe components use CSS custom properties for theming. You can customize the appearance by overriding these variables in your CSS:\n\n```css\n:root {\n    /* Focus and interaction colors */\n    --reorderable-focus-color: #007acc;\n    --reorderable-focus-offset: 2px;\n    --reorderable-focus-radius: 3px;\n    \n    /* Drag clone appearance */\n    --reorderable-drag-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);\n    --reorderable-drag-opacity: 0.6;\n    --reorderable-drag-scale: 1.02;\n    \n    /* Keyboard tip styling */\n    --reorderable-keyboard-tip-bg: #016DB6;\n    --reorderable-keyboard-tip-color: white;\n    --reorderable-keyboard-tip-radius: 4px;\n    \n    /* Drop indicators (for tree component) */\n    --reorderable-drop-indicator-color: #007acc;\n    --reorderable-drop-indicator-radius: 2px;\n    --reorderable-drop-child-bg: rgba(0, 122, 204, 0.2);\n}\n```\n\n### Example: Dark Theme\n\n```css\n:root {\n    --reorderable-focus-color: #4fc3f7;\n    --reorderable-keyboard-tip-bg: #2196f3;\n    --reorderable-drop-indicator-color: #4fc3f7;\n    --reorderable-drag-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);\n}\n```\n\n### Example: Custom Brand Colors\n\n```css\n:root {\n    --reorderable-focus-color: #6366f1;\n    --reorderable-keyboard-tip-bg: #4f46e5;\n    --reorderable-drop-indicator-color: #6366f1;\n    --reorderable-drop-child-bg: rgba(99, 102, 241, 0.1);\n}\n```\n\n## Tree Component\n\n### Tree Demo\n\n![Tree Demo](https://raw.githubusercontent.com/LexRiver/svelte-reorderable-list/main/static/img/tree.gif)\n\n### Tree Keyboard Navigation\n\nUse `Tab` key to focus element and then `Ctrl`+`Arrows` to move.\n\n![Tree Keyboard Demo](https://raw.githubusercontent.com/LexRiver/svelte-reorderable-list/main/static/img/tree-keyboard.gif)\n\nThe library also includes a `ReorderableTree` component for hierarchical data. It supports two input modes:\n\n### Tree Mode (Hierarchical Structure)\n\n```svelte\n\u003cscript\u003e\n    import { ReorderableTree, type TreeNode } from 'svelte-reorderable-list';\n\n    let treeNodes: TreeNode\u003c{ id: string; name: string; }\u003e[] = [\n        {\n            item: { id: '1', name: 'Parent 1' },\n            children: [\n                { item: { id: '1-1', name: 'Child 1.1' } },\n                { item: { id: '1-2', name: 'Child 1.2' } }\n            ]\n        },\n        {\n            item: { id: '2', name: 'Parent 2' },\n            children: [\n                { item: { id: '2-1', name: 'Child 2.1' } }\n            ]\n        }\n    ];\n\n    const getKey = (item) =\u003e item.id;\n\n    function handleTreeUpdate(updatedNodes) {\n        treeNodes = updatedNodes;\n    }\n\u003c/script\u003e\n\n{#snippet item(item, index)}\n    \u003cdiv class=\"tree-item\"\u003e\n        \u003cspan\u003e{item.name}\u003c/span\u003e\n    \u003c/div\u003e\n{/snippet}\n\n\u003cReorderableTree\n    treeNodes={treeNodes}\n    getKey={getKey}\n    onUpdate={handleTreeUpdate}\n    item={item}\n    levelPadding=\"20px\"\n/\u003e\n```\n\n### Flat Mode (Parent-Child References)\n\nFor 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:\n\n\n\n```svelte\n\u003cscript\u003e\n    import { ReorderableTree, type FlatTreeNode } from 'svelte-reorderable-list';\n\n    let flatNodes: FlatTreeNode\u003c{ id: string; name: string; }\u003e[] = [\n        { item: { id: '1', name: 'Parent 1' }, key: '1' },\n        { item: { id: '1-1', name: 'Child 1.1' }, key: '1-1', parentKey: '1' },\n        { item: { id: '1-2', name: 'Child 1.2' }, key: '1-2', parentKey: '1' },\n        { item: { id: '2', name: 'Parent 2' }, key: '2' },\n        { item: { id: '2-1', name: 'Child 2.1' }, key: '2-1', parentKey: '2' }\n    ];\n\n    function handleFlatTreeUpdate(updatedNodes) {\n        flatNodes = updatedNodes;\n    }\n\u003c/script\u003e\n\n{#snippet item(item, index)}\n    \u003cdiv class=\"tree-item\"\u003e\n        \u003cspan\u003e{item.name}\u003c/span\u003e\n    \u003c/div\u003e\n{/snippet}\n\n\u003cReorderableTree\n    flatNodes={flatNodes}\n    onUpdate={handleFlatTreeUpdate}\n    item={item}\n    levelPadding=\"20px\"\n/\u003e\n```\n\n### Tree Component Props\n\nThe `ReorderableTree` component automatically detects the input mode based on the props provided.\n\n#### Tree Mode Props\n\n| Prop                | Type                                       | Required | Default     | Description                                                                                             |\n| ------------------- | ------------------------------------------ | -------- | ----------- | ------------------------------------------------------------------------------------------------------- |\n| `treeNodes`         | `TreeNode\u003cItemType\u003e[]`                     | Yes      | `undefined` | The array of tree nodes to be displayed.                                                               |\n| `getKey`            | `(item: ItemType) =\u003e string`               | Yes      | `undefined` | A function that returns a unique key for each item.                                                     |\n| `onUpdate`          | `(nodes: TreeNode\u003cItemType\u003e[]) =\u003e void`    | Yes      | `undefined` | Callback function that is called with the new tree structure after a change.                           |\n\n#### Flat Mode Props  \n\n| Prop                | Type                                            | Required | Default     | Description                                                                                             |\n| ------------------- | ----------------------------------------------- | -------- | ----------- | ------------------------------------------------------------------------------------------------------- |\n| `flatNodes`         | `FlatTreeNode\u003cItemType\u003e[]`                      | Yes      | `undefined` | The array of flat tree nodes with parentKey references.                                                |\n| `onUpdate`          | `(flatNodes: FlatTreeNode\u003cItemType\u003e[]) =\u003e void` | Yes      | `undefined` | Callback function that is called with the new flat structure after a change.                          |\n\n#### Common Props\n\n| Prop                | Type                                       | Required | Default     | Description                                                                                             |\n| ------------------- | ------------------------------------------ | -------- | ----------- | ------------------------------------------------------------------------------------------------------- |\n| `item`              | `Snippet\u003c[ItemType, number]\u003e`              | Yes      | `undefined` | A Svelte 5 snippet for rendering each item. It receives the item and its index.                         |\n| `disabled`          | `boolean`                                  | No       | `false`     | When `true`, the reordering functionality is disabled.                                                  |\n| `cssSelectorHandle` | `string`                                   | No       | `undefined` | A CSS selector for the drag handle. If not provided, the entire item is draggable.                      |\n| `levelPadding`      | `string`                                   | No       | `\"20px\"`    | CSS padding value for each nesting level.                                                              |\n\n#### Type Definitions\n\n```typescript\ninterface TreeNode\u003cItemType\u003e {\n    item: ItemType;\n    children?: TreeNode\u003cItemType\u003e[];\n}\n\ninterface FlatTreeNode\u003cItemType\u003e {\n    item: ItemType;\n    key: string;\n    parentKey?: string;\n}\n```\n\n### Choosing Between Tree and Flat Mode\n\n#### Use Tree Mode When:\n- Your data is naturally hierarchical (e.g., file systems, nested categories)\n- You prefer working with nested object structures\n- You need to maintain the tree structure in your existing data model\n\n#### Use Flat Mode When:\n- Your data comes from a database with parent-child relationships\n- You need easier state management and updates\n- You want to avoid deep nesting complexity\n- You're working with dynamic hierarchies that change frequently\n\nBoth modes provide identical functionality and user experience - the choice is purely about data structure preference.\n\n### Tree Keyboard Navigation\n\n-   Use `Tab` to focus on an item.\n-   `Ctrl + ↑/↓`: Move item up/down within the same level\n-   `Ctrl + ←`: Move item up one level (make it sibling of its parent)\n-   `Ctrl + →`: Make item a child of the previous item\n\n## Accessibility\n\n### General Accessibility Features\n\n-   Full keyboard navigation support\n-   ARIA attributes for screen readers\n-   Focus management with visible focus indicators\n-   Reduced motion support for users with vestibular disorders\n-   High contrast mode support\n\n### Keyboard Navigation\n\n#### List Component\n-   Use `Tab` to focus on an item.\n-   Once an item is focused, use `Ctrl + ArrowUp/ArrowDown` for vertical lists or `Ctrl + ArrowLeft/ArrowRight` for horizontal lists to move the item.\n\n#### Tree Component\n-   Use `Tab` to focus on an item.\n-   Once an item is focused, use the keyboard shortcuts described above for tree navigation. ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flexriver%2Fsvelte-reorderable-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flexriver%2Fsvelte-reorderable-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flexriver%2Fsvelte-reorderable-list/lists"}