dotansimha /
graphql-code-generator
A tool for generating code based on a GraphQL schema and GraphQL operations (query/mutation/subscription), with flexible support for custom plugins.
92/100 healthLoading repository data…
braiekhazem / repository
A flexible and customizable Kanban board component for React applications, built with TypeScript and modern drag-and-drop functionality powered by Atlassian's pragmatic-drag-and-drop.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
A flexible and customizable Kanban board component for React applications, built with TypeScript and modern drag-and-drop functionality powered by Atlassian's pragmatic-drag-and-drop.
Check out the live demo: https://react-kanban-kit.netlify.app/
npm install react-kanban-kit
# or
yarn add react-kanban-kit
# or
pnpm add react-kanban-kit
import { Kanban, dropHandler } from "react-kanban-kit";
import type { BoardData } from "react-kanban-kit";
const MyKanbanBoard = () => {
const [dataSource, setDataSource] = useState<BoardData>({
root: {
id: "root",
title: "Root",
children: ["col-1", "col-2", "col-3"],
totalChildrenCount: 3,
parentId: null,
},
"col-1": {
id: "col-1",
title: "To Do",
children: ["task-1", "task-2"],
totalChildrenCount: 2,
parentId: "root",
},
"col-2": {
id: "col-2",
title: "In Progress",
children: ["task-3"],
totalChildrenCount: 1,
parentId: "root",
},
"col-3": {
id: "col-3",
title: "Done",
children: ["task-4"],
totalChildrenCount: 1,
parentId: "root",
},
"task-1": {
id: "task-1",
title: "Design Homepage",
parentId: "col-1",
children: [],
totalChildrenCount: 0,
type: "card",
content: {
description: "Create wireframes and mockups for the homepage",
priority: "high",
},
},
"task-2": {
id: "task-2",
title: "Setup Database",
parentId: "col-1",
children: [],
totalChildrenCount: 0,
type: "card",
},
"task-3": {
id: "task-3",
title: "Build Auth Flow",
parentId: "col-2",
children: [],
totalChildrenCount: 0,
type: "card",
},
"task-4": {
id: "task-4",
title: "Deploy to Production",
parentId: "col-3",
children: [],
totalChildrenCount: 0,
type: "card",
},
});
const configMap = {
card: {
render: ({ data }) => (
<div className="kanban-card">
<h3>{data.title}</h3>
{data.content?.description && <p>{data.content.description}</p>}
{data.content?.priority && (
<span className={`priority ${data.content.priority}`}>
{data.content.priority}
</span>
)}
</div>
),
isDraggable: true,
},
};
return (
<Kanban
dataSource={dataSource}
configMap={configMap}
onCardMove={(move) => {
setDataSource(dropHandler(move, dataSource, () => {}));
}}
/>
);
};
const configMap = {
card: {
render: ({ data, column, index, isDraggable }) => (
<div className="task-card">
<h4>{data.title}</h4>
<p>{data.content?.description}</p>
<div className="card-footer">
<span className="assignee">{data.content?.assignee}</span>
<span className="due-date">{data.content?.dueDate}</span>
</div>
</div>
),
isDraggable: true,
},
divider: {
render: ({ data }) => (
<div className="divider">
<hr />
<span>{data.title}</span>
</div>
),
isDraggable: false,
},
footer: {
render: ({ data, column }) => (
<button className="add-card-btn">+ Add card to {column.title}</button>
),
isDraggable: false,
},
};
<Kanban
dataSource={dataSource}
configMap={configMap}
renderColumnHeader={(column) => (
<div className="custom-header">
<h3>{column.title}</h3>
<span className="count">{column.totalChildrenCount}</span>
<button className="column-menu">⋯</button>
</div>
)}
renderColumnFooter={(column) => (
<div className="column-footer">
<button>Add New Card</button>
</div>
)}
// Column adder
allowColumnAdder={true}
renderColumnAdder={() => (
<button className="add-column-btn">+ Add Column</button>
)}
// List footer (shown at the bottom of each column's card list)
allowListFooter={(column) => column.id !== "done"}
renderListFooter={(column) => (
<div className="list-footer">
<button>+ Add another card</button>
</div>
)}
/>
Enable column reordering by dragging column headers. Columns are dragged by their header element and show a placeholder indicator at the drop position.
import { Kanban, dropColumnHandler } from "react-kanban-kit";
<Kanban
dataSource={dataSource}
configMap={configMap}
allowColumnDrag
onColumnMove={(move) => {
setDataSource(dropColumnHandler(move, dataSource));
}}
renderColumnHeader={(column) => (
<div style={{ cursor: "grab" }}>
<h3>{column.title}</h3>
</div>
)}
/>;
onColumnMove fires with { columnId, fromIndex, toIndex }dropColumnHandler utility to produce the updated dataSourceBy default, the drag preview is a DOM clone of the column. Override it with renderColumnDragPreview:
<Kanban
allowColumnDrag
renderColumnDragPreview={(column, info) => (
<div
style={{
width: info.state.dragging.width,
height: info.state.dragging.height,
backgroundColor: "#fff",
borderRadius: "12px",
padding: "12px",
boxShadow: "0 12px 30px rgba(0,0,0,0.2)",
transform: "rotate(4deg)",
}}
>
<strong>{column.title}</strong>
<p>{column.totalChildrenCount} cards</p>
</div>
)}
/>
By default, the drop indicator is a column-sized placeholder box. Override it with renderColumnDragIndicator:
<Kanban
allowColumnDrag
renderColumnDragIndicator={(column, info) => (
<div
style={{
width: 4,
height: info.height,
backgroundColor: "#4a90d9",
borderRadius: 4,
}}
/>
)}
/>
The info object provides { width, height, edge } where edge is "left" or "right" indicating which side of the target column the indicator appears on.
Set isDraggable: false on individual BoardItem entries to lock specific columns in place:
const dataSource = {
// ...
"col-1": {
id: "col-1",
title: "Backlog",
isDraggable: false, // This column cannot be dragged
// ...
},
};
<Kanban
renderCardDragPreview={(card, info) => (
<div className="drag-preview">
<h4>{card.title}</h4>
</div>
)}
renderCardDragIndicator={(card, info) => (
<div className="drop-indicator" style={{ height: info.height }} />
)}
onCardDndStateChange={(info) => {
if (info.state.type === "is-dragging") {
// Card is being dragged
}
}}
onColumnDndStateChange={(info) => {
if (info.state.type === "is-card-over") {
// A card is being dragged over this column
}
}}
/>
<Kanban
rootClassName="my-kanban-board"
rootStyle={{ backgroundColor: "#f5f5f5", padding: "20px" }}
columnWrapperStyle={(column) => ({
border: `2px solid ${column.content?.color || "#ddd"}`,
})}
columnWrapperClassName={(column) =>
`column-wrapper ${column.content?.theme || "default"}`
}
columnHeaderStyle={(column) => ({
backgroundColor: column.content?.headerColor || "#f8f9fa",
})}
columnStyle={(column) => ({
minHeight: column.totalChildrenCount > 10 ? "800px" : "400px",
})}
columnClassName={(column) =>
column.totalChildrenCount === 0 ? "empty-column" : "has-items"
}
cardWrapperStyle={(card, column) => ({
opacity: card.content?.archived ? 0.5 : 1,
})}
cardWrapperClassName="custom-card-wrapper"
cardsGap={12}
columnListContentStyle={(column) => ({
padding: column.totalChildrenCount === 0 ? "40px 16px" : "8px",
})}
columnListContentClassName={(column) =>
`column-content ${column.totalChildrenCount === 0 ? "empty" : "filled"}`
}
/>
<Kanban dataSource={dataSource} configMap={configMap} viewOnly={true} />
Infinite scroll lets each column load cards on demand as the user scrolls, instead of loading everything upfront.
The library uses totalChildrenCount and the actual children array to determine how many skeleton placeholders to render. When totalChildrenCount > children.length, the board renders skeleton cards to fill the gap. As the user scrolls and those skeletons become visible in the viewport, the library automatically calls your loadMore(columnId) callback.
For a full working implementation, see the Infinite Scroll example in the demo or try it live at react-kanban-kit.netlify.app.
dropHandler utilityWhen a card is dropped, onCardMove gives you the move details. Use dropHandler to produce the updated dataSource:
import { dropHandler } from "react-kanban-kit";
onCardMove={(move) => {
setDataSource(
dropHandler(
move,
dataSource,
() => {}, // called with the moved card (optional)
(targetColumn) => ({ // optional: update the target column
...targetColumn,
totalChildrenCount: targetColumn.totalChildrenCount + 1,
}),
(sourceColumn) => ({ // optional: update the source column
...sourceColumn,
totalChildrenCount: sourceColumn.totalChildrenCount - 1,
})
)
);
}}
dropColumnHandler utilityWhen a column is dropped, onColumnMove gives you the move details. Use dropColumnHandler to produce the updated dataSource:
import { dropColumnHandler } from "react-kanban-kit";
onColumnMove={(move) => {
setDataSource(dropColumnHandler(move, dataSource));
}}
dropColumnHandler reorders the root.children array to move the column from fromIndex to toIndex.
| Prop | Type | Description |
|---|---|---|
dataSource | BoardData | Required. The data structure for the board |
configMap | ConfigMap | Required. Configuration for different card types |
viewOnly | boolean | Disable all drag and drop interactions |
| Prop | Type | Description
Selected from shared topics, language and repository description—not editorial ratings.
dotansimha /
A tool for generating code based on a GraphQL schema and GraphQL operations (query/mutation/subscription), with flexible support for custom plugins.
92/100 health2FastLabs /
Flexible and powerful framework for managing multiple AI agents and handling complex conversations
94/100 healthSplidejs /
Splide is a lightweight, flexible and accessible slider/carousel written in TypeScript. No dependencies, no Lighthouse errors.
90/100 healthgoogle /
An open-source, code-first Typescript toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.
87/100 healthchansee97 /
A simple and flexible admin template based on Vue3, Vite, TypeScript, NaiveUI
90/100 healththisuxhq /
A lightweight, flexible drag and drop library for Svelte 5 applications.
88/100 health