Viselect: drag-to-select for the DOM, with React, Preact and Vue 3 bindings
✨ Viselect - A high performance and lightweight library to add a visual way of selecting elements, just like on your Desktop. Zero dependencies, super small. Support for major frameworks!
At a glance
- What is it?
- Viselect is a dependency-free TypeScript library that adds desktop-style marquee selection to web interfaces, with first-party framework packages. The core is small and the configuration surface is wide, but the documentation is thin on rollback and on how selection state interacts with your own data model.
- Who is it for?
- Adopt Viselect when you need marquee, click and Shift range selection over a grid or list that you already render yourself, and when you want the selection logic to live in the DOM rather than in your state store. Skip it if you need a full data grid with virtualized rows, sorting and editing, because Viselect only handles the selection gesture and the element registry.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 18 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Viselect addresses: marquee selection without building an input system
Desktop file managers let you drag a rectangle across a canvas and select everything it touches. Browsers give you that behaviour for free only inside text content. For a grid of cards, a list of rows, or a canvas of nodes, you have to build the gesture yourself: track pointer down, follow pointer move, compute which elements intersect the rectangle, handle Shift for ranges, handle touch, and keep the whole thing in sync when the list re-renders.
Viselect packages that gesture. The README describes it as a "Visual dom-selection library" and lists drag, click/tap and Shift range selection as the interaction set. It is aimed at engineers building file browsers, media pickers, kanban boards, image galleries, or any interface where the user selects a subset of rendered elements. The framework-ready claim is backed by first-party React, Preact and Vue 3 packages around a dependency-free core, so the same selection semantics are available whether you render with a component tree or plain DOM calls.
The scope boundary matters. Viselect owns the selection gesture and the registry of selectable elements. It does not own your data, your rendering, or your persistence. If you expect it to be a data grid, it is not one.
How the mechanism works: a selectable registry plus a rectangle that intersects it
The repository is a pnpm workspace. The top level holds a private root package.json, a pnpm-workspace.yaml, and a packages/ directory, which is where the core and the framework bindings live. The README names the vanilla build as @viselect/vanilla and refers to the UMD bundle at dist/viselect.umd.js, which is what the size badges measure. That layout tells you the intended consumption path: import the core, or import a framework wrapper that wraps the core.
The behavioural model is a rectangle that intersects elements. The README lists "selection triggers, thresholds, intersections, and overlap handling" as configurable behaviour. Thresholds and intersection rules are the part worth reading closely before you adopt: a drag that barely clips a card can either count as a selection or not, and that decision changes how the interface feels. Overlap handling covers the case where the rectangle covers only part of an element.
Lifecycle events are the second half of the mechanism. The README says you can "observe or cancel interactions at every selection stage". Cancellation is what makes the library usable inside a larger application: you can refuse a selection change that would violate a business rule, rather than mutating state and reverting it afterwards. The programmatic API covers managing selections, refreshing selectable elements, and enabling or disabling selection, which is the escape hatch for lists that change after the initial render.
Installing Viselect and running a first selection
The README does not inline install commands; it points to the documentation and the quickstart page at simonwep.github.io/viselect. The package names visible in the repository and README are @viselect/vanilla for the core and framework packages for React, Preact and Vue 3. A typical install with pnpm looks like this.
pnpm add @viselect/vanillaThe root package.json pins [email protected] and requires Node ^24 in engines, so if you build the repository itself rather than consuming the published package, match those. Building from source uses the workspace scripts.
pnpm install
pnpm build
pnpm testFor a first real use, the shape is: mark the elements you want selectable, instantiate the selection over a boundary element, and read the resulting selection from the event payload. The README does not reproduce a full snippet, so treat the quickstart page as the source of truth for the exact option names and event signatures. What you should verify on that page before writing code is which option controls the selection trigger, how the boundary element is passed, and what the event handler receives.
The docs site is built with VitePress and runs on port 3033 locally.
pnpm docs:devThat is the fastest way to read the quickstart and examples against the version you installed, since the published site may be ahead of or behind your lockfile.
Where Viselect stops being the right tool
Viselect does not render anything. If your list has ten thousand rows and you rely on windowing to keep the DOM small, the selection rectangle only knows about elements that are currently mounted. Scrolling during a drag means elements enter and leave the registry, and the README's mention of "refresh selectable elements" exists precisely because the set is not static. Whether a selection survives a refresh is a question the README does not answer, and that is the first thing to test in a real list.
Touch and scroll are listed as supported, including two-axis scrollable containers, but the README does not describe how a drag gesture is disambiguated from a scroll gesture on touch devices. That is a genuine design tension: on a phone, a drag is usually a scroll. If your interface is primarily mobile, budget time for testing the interaction rather than assuming the desktop behaviour transfers.
The library also assumes you want DOM-level selection. If your rows are virtualized, or if selection state is the source of truth for a server-side operation, you may prefer to compute intersections in your own state layer where you control the data model directly. Viselect is a gesture layer, and adding it on top of a state layer that already tracks selection gives you two sources of truth to reconcile.
How Viselect differs from Pickr and from a hand-rolled selection layer
The most common adjacent project in search results is Simonwep/pickr, by the same author. Pickr is a colour picker: it owns a small piece of UI and a value, and it renders its own interface. Viselect is the opposite kind of library. It renders nothing and instead attaches behaviour to elements you already render. If you arrived looking for a colour picker, you are in the wrong repository.
The closer alternative is writing the selection layer yourself. A hand-rolled version is perhaps a hundred lines: pointer events, a bounding box, and an intersection test against cached element rectangles. What you gain from doing it yourself is full control over the data model and no dependency. What you lose is the parts that are tedious rather than hard: Shift range selection, touch handling, two-axis scroll containers, threshold and overlap tuning, and lifecycle hooks that let you veto a change. Those are exactly the features the README enumerates.
A third option is a full data grid component. Grids ship selection as one feature among sorting, filtering, editing and virtualization. If you need those, a grid is the better fit and Viselect would be redundant. If you only need the selection gesture over markup you control, a grid is a large dependency for a small problem.
Maintenance, versioning and licence cost
The repository is not archived, and the last push was on 2026-09-13. Releases are frequent enough to suggest the project is being kept current: v3.10.0 on 2026-08-27 and v3.10.1 on 2026-09-04. The gap before that is notable, with v3.9.0 dated 2025-01-16, so the release cadence is not uniform. Plan upgrades around minor versions rather than assuming a steady drip.
Upgrade cost is low for the core, because the public surface described in the README is small: configuration options, lifecycle events, and a programmatic API. The risk sits in the framework packages, where a major version of React, Preact or Vue can force a binding update. The root package.json targets Node ^24 and [email protected] for development, which is a modern toolchain; if your CI runs an older Node, you will notice when building from source even though the published package does not carry that constraint.
The licence is MIT, declared in the root package.json and in the LICENSE file. That permits commercial use and modification with attribution and without a copyleft obligation on your own code. It is a permissive licence, not a legal opinion; check it against your organisation's policy if you redistribute the library.
Editorial conclusion
Adopt Viselect when you need marquee, click and Shift range selection over a grid or list that you already render yourself, and when you want the selection logic to live in the DOM rather than in your state store. Skip it if you need a full data grid with virtualized rows, sorting and editing, because Viselect only handles the selection gesture and the element registry. Before committing, verify two things in the docs and the packages directory: which selection trigger and overlap settings your target interaction needs, and whether the framework package you intend to use exposes the lifecycle events you need to cancel a drag.
Frequently asked questions
Does Viselect work with React?
Yes. The README lists first-party React, Preact and Vue 3 packages alongside the dependency-free core, and the repository topics include react, preact and vue. The core package referenced in the README is @viselect/vanilla.
What is @viselect/vanilla and when should I use it instead of a framework package?
It is the dependency-free core build, published as a UMD bundle at dist/viselect.umd.js according to the README badges. Use it when you render with plain DOM calls or a framework that has no first-party binding, and use the React, Preact or Vue 3 package when one exists for your stack.
Does Viselect handle touch input and scrollable containers?
The README states that it is touch and scroll aware and works with touch input and two-axis scrollable containers. It does not describe how a drag is distinguished from a scroll on touch devices, so test that interaction on your target devices.
What licence does Viselect use?
MIT. The licence is declared in the root package.json and in the LICENSE file at the top level of the repository.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/simonwep-viselect)