Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component...
npx skills add atman-33/skills --skill "dnd-kit-implementation"
Install specific skill from multi-skill repository
# Description
Guide for implementing sortable and droppable components using dnd-kit library. Use this skill when building React applications that require drag-and-drop functionality with both container reordering (useSortable) and item dropping (useDroppable) capabilities, such as Kanban boards, file management systems, or playlist editors.
# SKILL.md
name: dnd-kit-implementation
description: Guide for implementing sortable and droppable components using dnd-kit library. Use this skill when building React applications that require drag-and-drop functionality with both container reordering (useSortable) and item dropping (useDroppable) capabilities, such as Kanban boards, file management systems, or playlist editors.
dnd-kit Implementation Guide
Overview
This skill provides patterns for implementing drag-and-drop functionality using dnd-kit library that supports both sortable containers and droppable targets simultaneously.
Core Concept
The key to combining useSortable and useDroppable is conditional logic based on drag context:
- When dragging items β containers act as drop-only targets
- When dragging containers β containers act as sortable elements
This is achieved by detecting what's currently being dragged and enabling only the appropriate functionality.
Implementation Pattern
Container Component Structure
const SortableDroppableContainer = ({ container }) => {
// useSortable for container reordering
const {
attributes,
listeners,
setNodeRef: setSortableRef,
transform,
transition,
isDragging,
} = useSortable({ id: container.id });
// useDroppable for receiving items
const { setNodeRef: setDroppableRef, isOver } = useDroppable({
id: container.id,
});
// Active element from context
const { active } = useDndContext();
// Determine behavior based on what's being dragged
const isItem = active?.id?.toString().startsWith('item-');
const isContainer = active?.id?.toString().startsWith('container-');
// Apply conditional refs
const setNodeRef = isItem ? setDroppableRef : setSortableRef;
return (
<div ref={setNodeRef} {...(isContainer ? attributes : {})} style={style}>
<div {...(isContainer ? listeners : {})}>{/* Drag handle */}</div>
{/* Container content */}
</div>
);
};
Key Implementation Points
- Dual Hook Usage: Use both
useSortableanduseDroppablein the same component - Context Detection: Use
useDndContext()to check what's being dragged - Conditional Refs: Apply the appropriate ref based on drag state
- ID Naming Convention: Use prefixes like
container-*anditem-*to distinguish types
ID Naming Convention
// Containers
const containerId = `container-${id}`;
// Items
const itemId = `item-${id}`;
This convention makes conditional logic clean and maintainable.
State Management Critical Point
When updating container items, always create new objects:
// β Won't trigger re-render
containers.items.push(newItem);
// β
Correct - creates new reference
setContainers(prev => prev.map(c =>
c.id === targetId
? { ...c, items: [...c.items, newItem] }
: c
));
Common Use Cases
- Kanban Boards: Reorder columns and move cards between columns
- File Management: Reorganize folders and move files into folders
- Playlist Editors: Reorder playlists and add songs to playlists
- Task Managers: Reorder task lists and move tasks between lists
References
For detailed implementation examples and code patterns, see:
- implementation-patterns.md - Complete component examples with TypeScript
- state-management.md - State update patterns and common pitfalls
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.