← Back to Portfolio

@dnd-block-tree

A modular drag-and-drop tree toolkit split into two packages — a framework-agnostic core and a React adapter. Bring your own components; the library handles the complexity of nested, reorderable block structures.

PackageDescription
@dnd-block-tree/coreFramework-agnostic core — zero dependencies, pure TypeScript
@dnd-block-tree/reactReact adapter — drag-and-drop hierarchical block trees

Published on npm with full TypeScript support and cryptographic provenance via GitHub Actions OIDC.

Live Demo

12/20
Frontend
Components
Button
Modal
Hooks
useAuth
Backend
API Routes
/users
/posts
Infrastructure
Docker setup
Structure Diff
Frontend0
Components0
·Button0
·Modal1
Hooks1
·useAuth0
Backend1
API Routes0
·/users0
·/posts1
Infrastructure2
·Docker setup0
moved added removed

Drag items to reorder or reparent. Sections can nest inside other sections. The minimap shows a live structural diff — yellow indicates moved blocks.

Installation

npm install @dnd-block-tree/react

The React package depends on @dnd-block-tree/core, which is installed automatically.

Quick Start

import { BlockTree, type BaseBlock, type BlockRenderers } from '@dnd-block-tree/react'

interface MyBlock extends BaseBlock {
  type: 'section' | 'task' | 'note'
  title: string
}

const CONTAINER_TYPES = ['section'] as const

const renderers: BlockRenderers<MyBlock, typeof CONTAINER_TYPES> = {
  section: (props) => <SectionBlock {...props} />,
  task: (props) => <TaskBlock {...props} />,
  note: (props) => <NoteBlock {...props} />,
}

function App() {
  const [blocks, setBlocks] = useState<MyBlock[]>(initialBlocks)
  return (
    <BlockTree
      blocks={blocks}
      renderers={renderers}
      containerTypes={CONTAINER_TYPES}
      onChange={setBlocks}
    />
  )
}

Key Features

  • Weighted Collision Detection — Custom algorithm using edge distance with bottom bias for natural drag behavior
  • Smart Drop Zones — Only one before-zone rendered, none around active block
  • 8px Activation Distance — Prevents accidental drags while allowing normal clicks
  • Snapshot-Based Computation — State captured at drag start for consistent behavior
  • Debounced Preview — 150ms debounced virtual state for smooth drag previews
  • Type-Safe Renderers — Container blocks automatically get isExpanded and onToggleExpand props
  • Framework-Agnostic Core — Core logic has zero dependencies and can be used with any framework

Architecture

The library is split into two packages:

  • @dnd-block-tree/core — Normalized BlockIndex with Map-based byId and byParent lookups for O(1) operations. Block state managed through a reducer supporting add, insert, delete, and move operations. Framework-agnostic with zero dependencies.
  • @dnd-block-tree/react — React bindings built on @dnd-kit. Two factory-based providers: createBlockState<T>() (typed state management) and createTreeState<T>() (expand/collapse and drag state). Includes BlockTree, BlockTreeSSR, and BlockTreeDevTools components.

Tech Stack

  • @dnd-kit — drag-and-drop primitives
  • TypeScript — full type inference for container vs non-container renderers
  • React 18+ — hooks-based API
HomePortfolioBlogTILUses