Skip to content

RFC: drag drop headless controller pattern #5542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Rajdeepc
Copy link
Contributor

@Rajdeepc Rajdeepc commented Jun 13, 2025

RFC: Headless Drag & Drop Controllers for Spectrum Web Components

Overview

This RFC proposes a new headless controller-based architecture for implementing drag and drop (DnD) functionality in Spectrum Web Components. The design is inspired by React Spectrum's approach and aims to provide a flexible, accessible, and performant drag and drop system that can be used across various components.

Motivation

Current drag and drop implementations in web components often:

  • Couple drag/drop logic tightly with UI components
  • Lack comprehensive keyboard accessibility
  • Have inconsistent behavior across components
  • Make it difficult to reuse drag/drop logic
  • Don't fully support screen readers

Proposed Solution

Introduce two new reactive controllers:

1. DragController

export class DragController implements ReactiveController {
    constructor(host: ReactiveElement, options: DragControllerOptions);
    // Manages drag state, keyboard interactions, and accessibility
}

Key Features:

  • Keyboard support (Enter to grab, Tab to navigate, Enter to drop)
  • Screen reader announcements
  • Custom drag previews
  • ARIA attributes management
  • Event handling (dragstart, dragend, etc.)

2. DropController

export class DropController implements ReactiveController {
    constructor(host: ReactiveElement, options: DropControllerOptions);
    // Handles drop zones, validation, and visual feedback
}

Key Features:

  • Drop target validation
  • Visual feedback for valid/invalid drops
  • Custom drop operations
  • Event handling (dragenter, dragover, drop)

Technical Details

Controller Interfaces

export interface DragControllerOptions {
    getItems: () => DragItem[];
    onDragStart?: (event: DragStartEvent) => void;
    onDragEnd?: (event: DragEndEvent) => void;
    renderDragPreview?: (items: DragItem[]) => HTMLElement;
    disabled?: boolean;
}

export interface DropControllerOptions {
    acceptedTypes?: string[];
    onDrop?: (event: DropEvent) => void;
    onDropEnter?: (event: DropEvent) => void;
    onDropExit?: (event: DropEvent) => void;
    getDropOperation?: (types: Set<string>) => string;
    disabled?: boolean;
}

Usage Example

@customElement('sp-reorderable-item')
class ReorderableItem extends SpectrumElement {
    private dragController = new DragController(this, {
        getItems: () => [{
            'application/x-list-item': this.id,
            'text/plain': this.textContent
        }],
        renderDragPreview: (items) => {
            const preview = document.createElement('div');
            preview.textContent = items[0]['text/plain'];
            return preview;
        }
    });

    private dropController = new DropController(this, {
        acceptedTypes: ['application/x-list-item'],
        onDrop: (event) => {
            // Handle drop
        }
    });
}

Accessibility

The controllers implement:

  • Full keyboard navigation
  • ARIA attributes (aria-grabbed, aria-dropeffect)
  • Screen reader announcements
  • Focus management
  • High contrast support

Implementation Plan

  1. Phase 1: Core Controllers

    • Implement DragController and DropController
    • Add comprehensive tests
    • Document API and usage
  2. Phase 2: Example Components

    • Create sp-reorderable-list component
    • Add visual tests
    • Create documentation and examples
  3. Phase 3: Integration

    • Update existing components to use new controllers
    • Add performance benchmarks
    • Gather feedback from teams

Migration Strategy

  1. New components should use the controllers directly
  2. Existing components can be gradually migrated
  3. Provide migration guide and examples
  4. Support both old and new implementations during transition

Alternatives to be considered

  1. Custom Elements Approach

    • Pros: More declarative
    • Cons: Less flexible, harder to reuse
  2. Mixin-based Approach

    • Pros: Familiar to some developers
    • Cons: Less flexible, potential naming conflicts
  3. Event-based Only

    • Pros: Simpler implementation
    • Cons: Less control, harder to maintain

References

Copy link

changeset-bot bot commented Jun 13, 2025

⚠️ No Changeset found

Latest commit: b285280

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

Branch preview

Review the following VRT differences

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

@Rajdeepc Rajdeepc changed the title chore: drag drop controller first cut RFC: drag drop controller first cut Jun 13, 2025
@Rajdeepc Rajdeepc changed the title RFC: drag drop controller first cut RFC: drag drop controller headless controller pattern Jun 13, 2025
@Rajdeepc Rajdeepc self-assigned this Jun 13, 2025
@Rajdeepc Rajdeepc changed the title RFC: drag drop controller headless controller pattern RFC: drag drop headless controller pattern Jun 13, 2025
Copy link

Tachometer results

Currently, no packages are changed by this PR...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant