{"id":15288974,"url":"https://github.com/jagaapple/react-sortful","last_synced_at":"2025-04-13T06:32:04.068Z","repository":{"id":57345084,"uuid":"245005324","full_name":"jagaapple/react-sortful","owner":"jagaapple","description":"Sortable components for horizontal and vertical, nested, and tree forms.","archived":false,"fork":false,"pushed_at":"2020-07-21T12:52:27.000Z","size":895,"stargazers_count":34,"open_issues_count":7,"forks_count":8,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-26T23:11:18.923Z","etag":null,"topics":["arrange","dnd","drag","nest","react","sort","tree"],"latest_commit_sha":null,"homepage":"https://www.chromatic.com/library?appId=5e6025bcf2b5b700222c2c33","language":"TypeScript","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/jagaapple.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-04T21:13:57.000Z","updated_at":"2025-03-10T04:05:56.000Z","dependencies_parsed_at":"2022-09-16T18:11:23.946Z","dependency_job_id":null,"html_url":"https://github.com/jagaapple/react-sortful","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagaapple%2Freact-sortful","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagaapple%2Freact-sortful/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagaapple%2Freact-sortful/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagaapple%2Freact-sortful/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jagaapple","download_url":"https://codeload.github.com/jagaapple/react-sortful/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248674659,"owners_count":21143760,"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","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":["arrange","dnd","drag","nest","react","sort","tree"],"created_at":"2024-09-30T15:55:09.102Z","updated_at":"2025-04-13T06:32:03.172Z","avatar_url":"https://github.com/jagaapple.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003ereact-sortful\u003c/h1\u003e\n\n\u003ch4 align=\"center\"\u003e🔃 Sortable components for horizontal and vertical, nested, and tree forms. 🔄\u003c/h4\u003e\n\n\u003cimg src=\"./.docs/main.png\" width=\"896\" alt=\"Simple Vertical List, Nested Horizontal List, File Tree, Kanban, and Layers Panel\"\u003e\n\n```tsx\n\u003cList renderDropLine={renderDropLine} renderGhost={renderGhost} onDragEnd={onDragEnd}\u003e\n  \u003cItem identifier=\"a\" index={0}\u003eItem A\u003c/Item\u003e\n  \u003cItem identifier=\"b\" index={1} isGroup\u003e\n    \u003cdiv\u003eItem B (Group)\u003c/div\u003e\n    \u003cItem identifier=\"b-1\" index={0}\u003eNested Item B - 1\u003c/Item\u003e\n    \u003cItem identifier=\"b-2\" index={1}\u003eNested Item B - 2\u003c/Item\u003e\n  \u003c/Item\u003e\n  \u003cItem identifier=\"c\" index={2}\u003eItem C\u003c/Item\u003e\n\u003c/List\u003e\n```\n\n\u003cdiv align=\"center\"\u003e\n\u003ca href=\"https://www.npmjs.com/package/react-sortful\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/react-sortful.svg\" alt=\"npm\"\u003e\u003c/a\u003e\n\u003ca href=\"https://circleci.com/gh/jagaapple/react-sortful\"\u003e\u003cimg src=\"https://img.shields.io/circleci/project/github/jagaapple/react-sortful/master.svg\" alt=\"CircleCI\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/jagaapple/react-sortful\"\u003e\u003cimg src=\"https://img.shields.io/codecov/c/github/jagaapple/react-sortful.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.chromaticqa.com/library?appId=5e6025bcf2b5b700222c2c33\"\u003e\u003cimg src=\"https://img.shields.io/static/v1?label=catalogs\u0026message=storybook\u0026color=ff69b4\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/github/license/jagaapple/react-sortful.svg\" alt=\"license\"\u003e\u003c/a\u003e\n\u003ca href=\"https://twitter.com/jagaapple_tech\"\u003e\u003cimg src=\"https://img.shields.io/badge/contact-%40jagaapple_tech-blue.svg\" alt=\"@jagaapple_tech\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n## Table of Contents\n\n\u003c!-- TOC depthFrom:2 --\u003e\n\n- [Table of Contents](#table-of-contents)\n- [Features](#features)\n  - [Why react-sortful](#why-react-sortful)\n  - [Basic API Design](#basic-api-design)\n- [Quick Start](#quick-start)\n  - [Requirements](#requirements)\n  - [Installation](#installation)\n- [API](#api)\n  - [`List` Component](#list-component)\n    - [`renderDropLine` Prop](#renderdropline-prop)\n    - [`renderGhost` Prop](#renderghost-prop)\n    - [`renderPlaceholder` Prop](#renderplaceholder-prop)\n    - [`renderStackedGroup` Prop](#renderstackedgroup-prop)\n    - [`stackableAreaThreshold` Prop](#stackableareathreshold-prop)\n    - [`direction` Prop](#direction-prop)\n    - [`onDragStart` Prop](#ondragstart-prop)\n    - [`onDragEnd` Prop](#ondragend-prop)\n  - [`Item` Component](#item-component)\n    - [`isLonely` Prop](#islonely-prop)\n  - [`DragHandle` Component](#draghandle-component)\n- [Examples](#examples)\n- [Road map](#road-map)\n- [Contributing to react-sortful](#contributing-to-react-sortful)\n- [License](#license)\n\n\u003c!-- /TOC --\u003e\n\n\n## Features\n| FEATURES                                   | WHAT YOU CAN DO                                                       |\n|--------------------------------------------|-----------------------------------------------------------------------|\n| ⚛️ **Designed for React**                   | Get sortable components for your React project                        |\n| ✨ **Simple API**                           | All you need is to know Props of two components                       |\n| 🔄 **Support for vertical and horizontal** | You can create vertical and horizontal lists                          |\n| 👨‍👩‍👧‍👦 **Support for nested lists**         | You can stack lists in lists                                          |\n| 🌴 **Creatable any forms**                 | Easy to create a draggable file tree, Kanban, layers panel, and so on |\n| ❤️ **Ready for CSS and styled-components**  | Customize using your favorite styling way                             |\n| 🎩 **Type Safe**                           | You can use with TypeScript                                           |\n\nWhen you get interested in react-sortful, see [online catalogs (Storybook)](https://www.chromaticqa.com/library?appId=5e6025bcf2b5b700222c2c33)!\n\n\u003e 🚧 **react-sortful is currently in beta.**\n\u003e You can use react-sortful right now, but you might need to create pull requests for advanced use cases or fix for some bugs.\n\u003e Some of APIs will have breaking changes over time.\n\n\u003e 🙇🏻‍♂️ **Send me pull requests.**\n\u003e This was created to develop author's project and I don't have much time, please send me pull requests instead of issues.\n\u003e I will fix any bugs as soon as possible, but will not add new features for a while.\n\n### Why react-sortful\n\u003cimg src=\"./.docs/words.png\" width=\"896\" alt=\"What is a drop line, placeholder, and ghost\"\u003e\n\nThere are some awesome React libraries to implement drag and drop lists such as [react-beautiful-dnd](https://github.com/atlassian/react-beautiful-dnd)\nand [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc). These are very useful but I like classic design such\nas displaying a drop line and it's difficult to put a drop line in those libraries.\n\nAlso these libraries does not support nested lists or tree forms. react-sortful provides very simple API and make you to be able\nto create any draggable lists.\n\n**react-sortful is not for everyone**. If you don't like a drop line styles, I recommend to use those libraries instead!\n\n### Basic API Design\n```tsx\n// Flat List\n\u003cList\u003e\n  \u003cItem\u003e1\u003c/Item\u003e\n  \u003cItem\u003e2\u003c/Item\u003e\n  \u003cItem\u003e3\u003c/Item\u003e\n\u003c/List\u003e\n\n// Nested List\n\u003cList\u003e\n  \u003cItem\u003e1\u003c/Item\u003e\n  \u003cItem isGroup\u003e\n    \u003cItem\u003e2-1\u003c/Item\u003e\n    \u003cItem\u003e2-2\u003c/Item\u003e\n    \u003cItem\u003e2-3\u003c/Item\u003e\n  \u003c/Item\u003e\n  \u003cItem\u003e3\u003c/Item\u003e\n\u003c/List\u003e\n```\n\nAPI design of react-sortful is very simple. If you want to create a flat list, it's just to put `Item` in `List` as child components.\nIf you want to create a nested list, it's just put `Item` in a parent `Item` as child components and give `isGroup` Prop to the parent.\n\nActually you have to give some Props to `List` and `Item` and compose these items programmatically, but it's easy to create any\nlists if you don't forget this design.\n\n\n## Quick Start\n### Requirements\n- npm or Yarn\n- React 16.8.0 or higher ( `react` and `react-dom` packages )\n\n### Installation\n```bash\n$ npm install react-sortful\n```\n\nIf you are using Yarn, use the following command.\n\n```bash\n$ yarn add react-sortful\n```\n\n\n## API\n### `List` Component\n`List` is a top-level component in react-sortful. You have to wrap `Item` by `List` in any cases. `List` has some Props to control\na entire items.\n\n| PROP NAME                | TYPE                           | DEFAULT      | DESCRIPTION                                                                                                                                   |\n|--------------------------|--------------------------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------|\n| `renderDropLine`         | Function                       | *REQUIRED*   | A function to return an element used as a drop line. A drop line is a line to display a destination position to users.                        |\n| `renderGhost`            | Function                       | *REQUIRED*   | A function to return an element used as a ghost. A ghost is an element following a mouse pointer when dragging.                               |\n| `renderPlaceholder`      | Function                       |              | A function to return an element used as a placeholder. A placeholder is an element remaining in place when dragging the element.              |\n| `renderStackedGroup`     | Function                       |              | A function to return an element used when an empty group item is hovered by a dragged any item.                                               |\n| `itemSpacing`            | Number                         | `8`          | A spacing size (px) between items.                                                                                                            |\n| `stackableAreaThreshold` | Number                         | `8`          | A threshold size (px) of stackable area for group items.                                                                                      |\n| `direction`              | `\"vertical\"` or `\"horizontal\"` | `\"vertical\"` | A direction to recognize a drop area. Note that this will not change styles, so you have to apply styles such as being arranged side by side. |\n| `draggingCursorStyle`    | String                         |              | A cursor style when dragging.                                                                                                                 |\n| `isDisabled`             | Boolean                        | `false`      | Whether all items are not able to move, drag, and stack.                                                                                      |\n| `onDragStart`            | Function                       |              | A callback function after starting of dragging.                                                                                               |\n| `onDragEnd`              | Function                       | *REQUIRED*   | A callback function after end of dragging.                                                                                                    |\n| `onStackGroup`           | Function                       |              | A callback function when an empty group item is hovered by a dragged item.                                                                    |\n| `className`              | String                         |              |                                                                                                                                               |\n\n\u003e 🚫 **Styling Limitations.**\n\u003e When users drag any item, react-sortful needs to calculate a drop line position. To prevent low-performance while dragging,\n\u003e you have to give `itemSpacing` Prop as a spacing size between items if you want to specify margins.\n\u003e\n\u003e react-sortful gives the Prop value as `padding` style by `style` HTML attribute to `List` component, so you cannot overwrite padding\n\u003e parameters even if you give a CSS class name which has the style.\n\n#### `renderDropLine` Prop\n`renderDropLine` Prop requires to return a React element. Types of arguments are the following.\n\n|                 | TYPE                                                    | TYPE NAME (for TypeScript)      |\n|-----------------|---------------------------------------------------------|---------------------------------|\n| `injectedProps` | `{ ref: React.RefObject; style: React.CSSProperties; }` | `DropLineRendererInjectedProps` |\n\nNote that you have to pass `injectedProps` to a drop line element like the following, otherwise react-sortful does not work fine.\n\n```tsx\nconst renderDropLine = (injectedProps: DropLineRendererInjectedProps) =\u003e (\n  \u003cdiv ref={injectedProps.ref} style={injectedProps.style} className=\"drop-line\"\u003exxx\u003c/div\u003e\n);\n```\n\n#### `renderGhost` Prop\n`renderGhost` Prop requires to return a React element. Types of arguments are the following.\n\n|        | TYPE                                                                                   | TYPE NAME (for TypeScript) |\n|--------|----------------------------------------------------------------------------------------|----------------------------|\n| `meta` | `{ identifier: T; groupIdentifier: T \\| undefined; index: number; isGroup: boolean; }` | `GhostRendererMeta\u003cT\u003e`     |\n\n#### `renderPlaceholder` Prop\n`renderPlaceholder` Prop requires to return a React element. Types of arguments are the following.\n\n|                 | TYPE                                                                                   | TYPE NAME (for TypeScript)         |\n|-----------------|----------------------------------------------------------------------------------------|------------------------------------|\n| `injectedProps` | `{ style: React.CSSProperties; }`                                                      | `PlaceholderRendererInjectedProps` |\n| `meta`          | `{ identifier: T; groupIdentifier: T \\| undefined; index: number; isGroup: boolean; }` | `PlaceholderRendererMeta\u003cT\u003e`       |\n\nNote that you have to pass `injectedProps` to a placeholder element like the following, otherwise react-sortful does not work fine.\n\n```tsx\nconst renderPlaceholder = (injectedProps: PlaceholderRendererInjectedProps) =\u003e (\n  \u003cdiv style={injectedProps.style} className=\"placeholder\"\u003exxx\u003c/div\u003e\n);\n```\n\n#### `renderStackedGroup` Prop\n`renderStackedGroup` Prop requires to return a React element. Types of arguments are the following.\n\n|                 | TYPE                                                                 | TYPE NAME (for TypeScript)          |\n|-----------------|----------------------------------------------------------------------|-------------------------------------|\n| `injectedProps` | `{ style: React.CSSProperties; }`                                    | `StackedGroupRendererInjectedProps` |\n| `meta`          | `{ identifier: T; groupIdentifier: T \\| undefined; index: number; }` | `StackedGroupRendererMeta\u003cT\u003e`       |\n\nNote that you have to pass `injectedProps` to a stacked group item element like the following, otherwise react-sortful does not work fine.\n\n```tsx\nconst renderStackedGroup = (injectedProps: PlaceholderRendererInjectedProps) =\u003e (\n  \u003cdiv style={injectedProps.style} className=\"group stacked\"\u003exxx\u003c/div\u003e\n);\n```\n\n#### `stackableAreaThreshold` Prop\n\u003cimg src=\"./.docs/stackable-area-threshold.png\" width=\"896\" alt=\"Stackable Area Threshold\"\u003e\n\nIf an item is given `isGroup` Prop, the item will be recognized as a group item. react-sortful does not support for stacking items\non items, but you can stack any items on item groups.\n\nAll items has droppable areas on both sides. In addition, all group items has stackable areas. `stackableAreaThreshold` Prop is\nto configure the distance from droppable areas to a point of beginning of stackable areas.\nIf you want to set a hit box to be small, give a large value to the Prop.\n\n#### `direction` Prop\nIf you want to create horizontal lists, you have to give `\"horizontal\"` to `direction` Prop. react-sortful will change directions\nof droppable areas, but this will not affect styles. Aside from it, you need to style `Item` or its child elements in order to\narrange side by side.\n\n#### `onDragStart` Prop\nTypes of arguments are the following.\n\n|        | TYPE                                                                                   | TYPE NAME (for TypeScript) |\n|--------|----------------------------------------------------------------------------------------|----------------------------|\n| `meta` | `{ identifier: T; groupIdentifier: T \\| undefined; index: number; isGroup: boolean; }` | `DragStartMeta\u003cT\u003e`         |\n\n#### `onDragEnd` Prop\nTypes of arguments are the following.\n\n|        | TYPE                                                                                                                                                        | TYPE NAME (for TypeScript) |\n|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|\n| `meta` | `{ identifier: T; groupIdentifier: T \\| undefined; index: number; isGroup: boolean; nextGroupIdentifier: T \\| undefined; nextIndex: number \\| undefined; }` | `DragEndMeta\u003cT\u003e`           |\n\nWhen `meta.nextIndex` is `undefined` , a dragged item will not change or will be stacked on a group item.\n\n### `Item` Component\n`Item` is used when you want to add items to a list. `Item` has some Props to control a specific item.\n\n| PROP NAME                  | TYPE             | DEFAULT    | DESCRIPTION                                                                                                                                 |\n|----------------------------|------------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------|\n| `identifier`               | Number or String | *REQUIRED* | A unique identifier in all items of list.                                                                                                   |\n| `index`                    | Number           | *REQUIRED* | A unique and sequential index number in a parent group.                                                                                     |\n| `isGroup`                  | Boolean          | `false`    | Whether an item is possible to have child items.                                                                                            |\n| `isLocked`                 | Boolean          | `false`    | Whether child items are not able to move and drag. Stacking and popping child items will be allowed. Grandchild items will not be affected. |\n| `isLonely`                 | Boolean          | `false`    | Whether droppable areas on both sides of an item is disabled.                                                                               |\n| `isUsedCustomDragHandlers` | Boolean          | `false`    | Whether an item contains custom drag handlers in child items (not grandchildren).                                                           |\n\n#### `isLonely` Prop\nAll items, contains item groups, have droppable areas on both sides. This Prop disables it, but note that this will not affect to\ndroppable areas of adjacent items.\n\n### `DragHandle` Component\nBy default, elements wrapped by `Item` are possible to drag and drop. If you want to limit a draggable range, `DragHandle` would\nbe needed.\n\n| PROP NAME   | TYPE   | DEFAULT | DESCRIPTION |\n|-------------|--------|---------|-------------|\n| `className` | String |         |             |\n\n\u003e 🚫 **Placeholder Limitations.**\n\u003e If you use `DragHandle` in some items, **don't forget containing `DragHandle` in a placeholder element** in the items,\n\u003e otherwise drag and drop will not work fine.\n\n\n## Examples\nYou can see more examples from [online catalogs (Storybook)](https://www.chromaticqa.com/library?appId=5e6025bcf2b5b700222c2c33)!\n\n- [Simple Horizontal List](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=1%20Simple%20(horizontal)\u0026buildNumber=37\u0026specName=Dynamic)\n- [Nested Horizontal List](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=2%20Nested%20(horizontal)\u0026buildNumber=37\u0026specName=Dynamic)\n- [Simple Vertical List](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=1%20Simple%20(vertical)\u0026buildNumber=37\u0026specName=Dynamic)\n- [Nested Vertical List](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=2%20Nested%20(vertical)\u0026buildNumber=37\u0026specName=Dynamic)\n- [Custom Drag Handle](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=3%20Advanced%20Examples\u0026buildNumber=37\u0026specName=Custom%20drag%20handle)\n- [Tree](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=3%20Advanced%20Examples\u0026buildNumber=37\u0026specName=Tree)\n- [Kanban](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=3%20Advanced%20Examples\u0026buildNumber=37\u0026specName=Kanban)\n- [Layers Panel](https://www.chromaticqa.com/component?appId=5e6025bcf2b5b700222c2c33\u0026name=3%20Advanced%20Examples\u0026buildNumber=37\u0026specName=Layers%20panel)\n\n\n## Road map\n\u003e 🙇🏻‍♂️ **Send me pull requests.**\n\u003e I have plans to support for the following features, but I don't have time to implement them, so release dates are not decided.\n\u003e If you have much time, send me pull requests!\n\n- Virtual lists support\n- Mobile devices (touch events) support\n- Multi-drag support\n- Improve for semantic rendering\n- Remove some limitations\n\n\n## Contributing to react-sortful\nBug reports and pull requests are welcome on GitHub at\n[https://github.com/jagaapple/react-sortful](https://github.com/jagaapple/react-sortful). This project\nis intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the\n[Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\nPlease read [Contributing Guidelines](./.github/CONTRIBUTING.md) before development and contributing.\n\n\n## License\nThe library is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\nCopyright 2020 Jaga Apple. All rights reserved.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagaapple%2Freact-sortful","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjagaapple%2Freact-sortful","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagaapple%2Freact-sortful/lists"}