@badasukerubin/react-simple-drag-selection

中文文档
1.7.0发布于 2026/10/31MITTypeScriptESM + CJS零依赖构建来源已验证

A react library that provides an efficient and effective drag selection logic.

原始使用文档
文档目录10 节
  1. Install
  2. Usage
  3. useDragSelection
  4. Native controls and drag-and-drop
  5. Modifiers and selection ownership
  6. useDragSelected
  7. SelectionBox
  8. Host theme and colors
  9. Development
  10. Changes in 1.5

react-simple-drag-selection

A small React drag-selection library with mouse, pen and touch input, frame-batched updates, and continuous edge scrolling. React is its only runtime dependency.

Install

npm install @badasukerubin/react-simple-drag-selection

Supports React 16.8, 17, 18 and 19 in browsers with Pointer Events, DOMRect and requestAnimationFrame. Importing and rendering on the server does not access the DOM; gestures attach after mounting.

Usage

import { useContext, useRef } from "react";
import {
  DragSelectionContext,
  SelectionBox,
  useDragSelected,
  useDragSelection,
} from "@badasukerubin/react-simple-drag-selection";

function Item() {
  const elementRef = useRef<HTMLDivElement>(null);
  const selection = useContext(DragSelectionContext);
  const selected = useDragSelected({ elementRef, selection });

  return (
    <div ref={elementRef} style={{ background: selected ? "#aac4ff" : "#eee" }}>
      Select me
    </div>
  );
}

export function Example() {
  const containerRef = useRef<HTMLDivElement>(null);
  const boxRef = useRef<HTMLDivElement>(null);
  const selection = useDragSelection({ containerRef, boxRef });

  return (
    <DragSelectionContext.Provider value={selection}>
      <div ref={containerRef} style={{ height: 300, overflow: "auto" }}>
        <SelectionBox ref={boxRef} />
        <Item />
      </div>
    </DragSelectionContext.Provider>
  );
}

Render SelectionBox in the same document, typically beside the selectable content or in a React portal. React retains ownership of the element throughout the gesture. Keep layout styles on the container and visual styles on the box. Geometry, display, pointer events and positioning are managed by the hook.

useDragSelection

Returns a viewport-coordinate DOMRect | null, matching getBoundingClientRect().

OptionDefaultPurpose
containerRefRequiredSelection surface, including its scrollable content. Nullable refs are supported.
scrollContainerRefNoneOptional scrolling ancestor when the selection surface does not scroll itself.
boxRefRequiredRef to SelectionBox or an equivalent div in the same document.
mouseMoveThreshold5Movement must exceed this distance on either axis before drawing. Applies to mouse, pen and touch.
disabledfalseDisable gestures and clear the rectangle.
touchtrueEnable touch selection and temporarily apply touch-action: none to the container. Use false to retain native touch scrolling.
autoScrolltrueScroll the container near its edges. Use false or { edgeSize: 24, speed: 600 }. Distance is in CSS pixels; speed is pixels per second.
ignoreSelectorNoneAdditional valid CSS selector for targets that cannot start a gesture.
shouldStartSelectionNoneReturn false to reject a press. Receives its PointerEvent, including modifier keys.
onSelectionStartNoneCalled once on an accepted press, before crossing the threshold. Receives the PointerEvent.
onSelectionNoneReceives each changed rectangle, at most once per animation frame, plus a final flush on release when needed.
onSelectionEndNoneReceives { selection, cancelled, event } on release or cancellation.

A successful release hides the box and retains the final rectangle. The next accepted press clears it. An ordinary click below the movement threshold keeps native click behavior. Escape, pointer cancellation, capture loss, a second pointer, window blur, page hiding, or native HTML dragging cancels the gesture and restores the previous rectangle. Disabling, replacing refs or unmounting tears down the gesture without calling application callbacks.

Callbacks use the latest committed props. Movement and scroll events share one animation frame. Auto-scroll continues while the pointer rests at an edge and stops at the scroll limit; it scrolls only the configured container (or its explicit scrollContainerRef ancestor) and its enabled overflow axes. Ancestor/window scrolling updates the anchor. Scroll offsets, borders, translation and positive axis-aligned scaling are accounted for.

Native controls and drag-and-drop

Inputs, textareas, selects, buttons, links, labels, summaries, editable content and native draggable elements cannot start selection. Descendants of .ignore-drag-selection and [data-ignore-drag-selection] are also excluded, including SVG targets and open shadow DOM event paths. Nested selection surfaces give the gesture to the innermost accepting surface.

<div className="ignore-drag-selection">
  <div draggable onDragStart={startNativeDrag}>
    Drag this item
  </div>
</div>

Only the click belonging to a completed drag is suppressed. Keyboard clicks, later pointer presses and unrelated controls retain their normal behavior.

Modifiers and selection ownership

The library measures a rectangle; your application owns item identities, keyboard navigation, additive selection and range selection. For example, use shouldStartSelection: event => !event.altKey to reserve Alt-drag for another interaction. Read shiftKey, ctrlKey and metaKey in onSelectionStart to choose how your application combines the gesture's matches with its existing selection. Use buttons or another keyboard-accessible control for non-pointer selection; drag selection must not be the only way to select an item.

useDragSelected

OptionDefaultPurpose
elementRefRequiredNullable ref to the item element. Read after the DOM commit.
selectionRequiredRectangle from the hook/context, or null.
collision"intersect"Use "contain" to require the whole item inside the rectangle.
onSelectedNoneReceives the new boolean only when membership changes, including deselection.

Returns a boolean. Hidden, zero-size elements and zero-area selection rectangles do not match. Touching rectangle edges count as intersection. Keep the item ref on the element representing the actual selectable area.

Virtualized lists can only measure mounted items. Store selected IDs in your application when selecting across virtual pages, and use your list's geometry/model for items that are not mounted. A retained rectangle is geometry, not a persistent ID-based selection. Rotated/skewed coordinate systems and cross-origin iframe gestures are outside the rectangular hit-test model. For unclipped overlays inside CSS paint containment or stacking contexts, render the box through a React portal into that document's body.

SelectionBox

Accepts normal div props and a forwarded ref. Defaults to a hidden, fixed, non-interactive, aria-hidden rectangle. Customize className, background, border and z-index; keep the hook's positioning and sizing properties free of CSS !important overrides.

Host theme and colors

The host supplies its resolved "light" or "dark" theme. Both use neutral gray: a dark fill/outline on light surfaces and a light fill/outline on dark surfaces. Omitting theme preserves the original light appearance. The package does not read system preferences, persist a theme, or add a theme provider.

<SelectionBox ref={boxRef} theme={isDark ? "dark" : "light"} />

// Optional custom colors, independent of the theme:
<SelectionBox
  ref={boxRef}
  theme="dark"
  backgroundColor="rgba(59, 130, 246, 0.2)"
  accentColor="var(--selection-accent, #60a5fa)"
/>
PropDefaultPurpose
theme"light"Host-resolved appearance. Pass the resolved mode for a host's system-theme setting.
backgroundColorTheme's translucent neutralFill color. Supply alpha for transparency; transparent disables the fill.
accentColorTheme's neutral outlineOutline color; does not tint the fill or selected items.

Color props accept CSS colors, including CSS variables. Each override is optional; removing it restores the theme default. Explicit style overrides take precedence (color also overrides the default outline's currentColor). Theme/color changes apply during a drag without resetting selection. Item highlights remain owned by your application. Public SelectionBoxProps and SelectionBoxTheme types are exported.

Development

Use Node.js 22.12 or newer.

npm ci
npm run typecheck
npm test
npx playwright install chromium firefox webkit
npm run test:browser
npm pack

The browser suite exercises the built distribution in Chromium at desktop, tablet portrait, tablet landscape and mobile sizes, plus Firefox and WebKit. Touch dragging is exercised through Chromium's real input protocol. BROWSER_CHANNEL=chrome npm run test:browser uses an installed Chrome for the Chromium projects. npm pack builds and checks types before producing the distributable tarball.

The example uses the local package via file:... Build the package first, then run npm ci and npm run dev in example. Rebuild the package when editing its source.

Changes in 1.5

The original hooks, context, React peer range and final-rectangle behavior remain. Pointer Events replace the separate mouse/touch listeners. Interactive targets are ignored automatically, end callbacks only fire for accepted gestures, and onSelected reports the new value on transitions. See CHANGELOG.md for fixes.

版本与发布记录

@badasukerubin/react-simple-drag-selection 共发布 8 个版本,首次发布于 2024/05/10;过去 12 个月发布了 2 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.7.0latest2026/10/312 天前
1.4.02026/01/189 个月前
1.3.02025/03/161.6 年前
1.2.02025/03/161.6 年前
1.1.12024/05/212 年前
1.1.02024/05/212 年前

关于 @badasukerubin/react-simple-drag-selection 的常见问题

@badasukerubin/react-simple-drag-selection 是什么?

一个react库,提供了一个高效的拖动选择逻辑。

如何安装 @badasukerubin/react-simple-drag-selection?

在项目目录运行 npm install @badasukerubin/react-simple-drag-selection,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@badasukerubin/react-simple-drag-selection 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@badasukerubin/react-simple-drag-selection 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@badasukerubin/react-simple-drag-selection 可以商用吗?

@badasukerubin/react-simple-drag-selection 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@badasukerubin/react-simple-drag-selection 还在维护吗?

最新版本 1.7.0 发布于 2026/10/31(2 天前);至今共发布 8 个版本,其中过去 12 个月发布了 2 个;首次发布于 2024/05/10。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。