S
Documentation

Drag & Drop

The SurveyBuilder uses native HTML5 drag-and-drop to let users reorder questions within a page and move questions between pages — no external libraries required.

How It Works

Native HTML5 API

The builder leverages the browser's built-in Drag and Drop API via draggable, onDragStart, onDragOver, and onDrop events. No third-party dependencies like react-dnd or dnd-kit are needed.

Zero Configuration

Drag-and-drop is enabled automatically in the SurveyBuilder. Each question card has a drag handle that users can grab to initiate a drag operation.

Visual Feedback

During a drag operation, drop targets are highlighted and the dragged item shows a ghost preview. The builder state tracks isDragging for custom styling.

Reordering Questions

Drag a question within the same page to reorder it. The builder dispatches a REORDER_QUESTIONS action:

Reorder Actiontypescript
// Internal action dispatched by the builder
dispatch({
  type: 'REORDER_QUESTIONS',
  payload: {
    pageId: 'page1',
    fromIndex: 0,  // original position
    toIndex: 2,    // new position
  },
});

Moving Between Pages

Drag a question from one page and drop it onto another page. The builder dispatches a MOVE_QUESTION action:

Move Actiontypescript
// Internal action dispatched by the builder
dispatch({
  type: 'MOVE_QUESTION',
  payload: {
    fromPageId: 'page1',
    toPageId: 'page2',
    fromIndex: 1,  // position in source page
    toIndex: 0,    // position in target page
  },
});

Reordering Pages

Pages themselves can also be reordered by dragging their tab headers:

Reorder Pages Actiontypescript
dispatch({
  type: 'REORDER_PAGES',
  payload: {
    fromIndex: 0,
    toIndex: 1,
  },
});

Builder State

BuilderStatetypescript
interface BuilderState {
  schema: SurveySchema;
  selectedQuestionId: string | null;
  selectedPageId: string | null;
  isDragging: boolean;  // true during a drag operation
}

All Builder Actions

BuilderActiontypescript
type BuilderAction =
  | { type: 'ADD_PAGE'; payload?: Partial<Page> }
  | { type: 'REMOVE_PAGE'; payload: { pageId: string } }
  | { type: 'UPDATE_PAGE'; payload: { pageId: string; updates: Partial<Page> } }
  | { type: 'ADD_QUESTION'; payload: { pageId: string; question?: Partial<Question> } }
  | { type: 'REMOVE_QUESTION'; payload: { pageId: string; questionId: string } }
  | { type: 'UPDATE_QUESTION'; payload: { pageId: string; questionId: string; updates: Partial<Question> } }
  | { type: 'REORDER_QUESTIONS'; payload: { pageId: string; fromIndex: number; toIndex: number } }
  | { type: 'REORDER_PAGES'; payload: { fromIndex: number; toIndex: number } }
  | { type: 'MOVE_QUESTION'; payload: { fromPageId: string; toPageId: string; fromIndex: number; toIndex: number } }
  | { type: 'SELECT_QUESTION'; payload: { questionId: string | null } }
  | { type: 'SELECT_PAGE'; payload: { pageId: string | null } }
  | { type: 'SET_SCHEMA'; payload: SurveySchema }
  | { type: 'SET_DRAGGING'; payload: boolean };

Browser Support

HTML5 drag-and-drop is supported in all modern browsers. On touch devices, the browser's native touch-to-drag behaviour applies. For more advanced touch support, consider adding a polyfill like mobile-drag-drop.