<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sakti Chourasia</title>
    <description>The latest articles on DEV Community by Sakti Chourasia (@shakcho).</description>
    <link>https://dev.to/shakcho</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3883649%2Ffb00f0ed-6d57-4108-8a37-fa3837d7abd8.jpg</url>
      <title>DEV Community: Sakti Chourasia</title>
      <link>https://dev.to/shakcho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shakcho"/>
    <language>en</language>
    <item>
      <title>I got tired of every "draggable" library being 30KB and opinionated about my CSS - so I built react-driftkit</title>
      <dc:creator>Sakti Chourasia</dc:creator>
      <pubDate>Fri, 17 Apr 2026 05:57:23 +0000</pubDate>
      <link>https://dev.to/shakcho/i-got-tired-of-every-draggable-library-being-30kb-and-opinionated-about-my-css-so-i-built-2k9i</link>
      <guid>https://dev.to/shakcho/i-got-tired-of-every-draggable-library-being-30kb-and-opinionated-about-my-css-so-i-built-2k9i</guid>
      <description>&lt;p&gt;&lt;em&gt;small, unstyled primitives for floating UI. No providers. No design system. Tree-shakable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3w8ragp574m1nu1l9hb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3w8ragp574m1nu1l9hb.gif" alt="React Drift demo" width="760" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You know the drill. You need a floating chat button, a side dock, a pull-up sheet, or a resizable split layout. You search npm. You find one of two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A 40KB monolith&lt;/strong&gt; that ships with its own design system, demands a &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; at the root, and renders animated 3D bevels on a button you wanted to style yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A drag library so low-level&lt;/strong&gt; you spend the next four hours wiring up viewport clamping, touch events, snap-on-release, and a &lt;code&gt;ResizeObserver&lt;/code&gt; so the thing doesn't fly off-screen when the user rotates their phone.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither is what I want. I want a thing that handles the &lt;em&gt;positioning and interaction&lt;/em&gt;, hands me a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, and gets out of the way.&lt;/p&gt;

&lt;p&gt;That's &lt;a href="https://www.npmjs.com/package/react-driftkit" rel="noopener noreferrer"&gt;&lt;strong&gt;react-driftkit&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-driftkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://react-driftkit.saktichourasia.dev/" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt; · &lt;a href="https://github.com/shakcho/react-drift" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/react-driftkit" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The design rule: one component, one job
&lt;/h2&gt;

&lt;p&gt;react-driftkit ships four primitives. Each one is independent, tree-shakable, unstyled, and a few KB gzipped. You import only what you use.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;MovableLauncher&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Drag-anywhere floating wrapper. Optional snap-to-corner.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;SnapDock&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edge-pinned dock that flips between horizontal and vertical when you drag it across edges.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;DraggableSheet&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull-up/down sheet with &lt;code&gt;peek&lt;/code&gt; / &lt;code&gt;half&lt;/code&gt; / &lt;code&gt;full&lt;/code&gt; snap points.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;ResizableSplitPane&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;N-pane resizable layout with localStorage-persisted ratios.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No &lt;code&gt;&amp;lt;DriftProvider&amp;gt;&lt;/code&gt;. No theme tokens. No CSS file you have to import. Your styles, your structure — the kit owns positioning and pointer math.&lt;/p&gt;




&lt;h2&gt;
  
  
  The four primitives, with code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;&amp;lt;MovableLauncher&amp;gt;&lt;/code&gt; — the floating chat button, done right
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MovableLauncher&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-driftkit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MovableLauncher&lt;/span&gt; &lt;span class="na"&gt;defaultPosition&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bottom-right"&lt;/span&gt; &lt;span class="na"&gt;snapToCorners&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"my-chat-btn"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;💬&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MovableLauncher&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole API for the common case. It handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mouse, touch, and pen via the Pointer Events API (one code path, not three)&lt;/li&gt;
&lt;li&gt;A 5px drag threshold so nested &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;s still receive clicks&lt;/li&gt;
&lt;li&gt;Auto-reposition when the viewport resizes or the child's size changes&lt;/li&gt;
&lt;li&gt;A bouncy snap-to-nearest-corner on release (when you opt in)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want pixel-precise control instead of corners:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MovableLauncher&lt;/span&gt; &lt;span class="na"&gt;defaultPosition&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Toolbar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MovableLauncher&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The wrapper is a &lt;code&gt;position: fixed&lt;/code&gt; &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; you can style however you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;&amp;lt;SnapDock&amp;gt;&lt;/code&gt; — VS Code / Figma-style edge dock
&lt;/h3&gt;

&lt;p&gt;This is the one I'm most proud of. Drag it to any edge of the viewport and it pins there. Drag it from the bottom edge to the left edge, and the layout &lt;em&gt;flips&lt;/em&gt; from horizontal to vertical with a FLIP-style animation anchored to the active edge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SnapDock&lt;/span&gt; &lt;span class="na"&gt;defaultEdge&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt; &lt;span class="na"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Search&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Settings&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;SnapDock&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wrapper exposes &lt;code&gt;data-edge&lt;/code&gt; and &lt;code&gt;data-orientation&lt;/code&gt; attributes, so you can drive any CSS you want without re-rendering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.my-dock&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-orientation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"vertical"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want to react in JS too?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SnapDock&lt;/span&gt;
  &lt;span class="na"&gt;defaultEdge&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"left"&lt;/span&gt;
  &lt;span class="na"&gt;onEdgeChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;moved to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onOffsetChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Toolbar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;SnapDock&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. &lt;code&gt;&amp;lt;DraggableSheet&amp;gt;&lt;/code&gt; — bottom sheets that don't suck on mobile
&lt;/h3&gt;

&lt;p&gt;If you've ever tried to build a Maps-style detail sheet from scratch, you know the pain: drag tracking, velocity-based snap, scroll containment, the works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DraggableSheet&lt;/span&gt; &lt;span class="na"&gt;snapPoints&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;peek&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;half&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;defaultSnap&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"half"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;data-handle&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sheet-handle"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sheet-body"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Filters, cart, details…&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DraggableSheet&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mix presets, raw pixels, and percentages in the same array. They get resolved against the drag axis at gesture time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DraggableSheet&lt;/span&gt; &lt;span class="na"&gt;snapPoints&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;peek&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;40%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Velocity matters. A fast flick advances one stop in the flick direction; a slow drag snaps to the nearest one. The &lt;code&gt;dragHandleSelector&lt;/code&gt; prop lets you confine drag to a handle strip so the sheet body keeps scrolling normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DraggableSheet&lt;/span&gt;
  &lt;span class="na"&gt;snapPoints&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;peek&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;half&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;dragHandleSelector&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"[data-handle]"&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;data-handle&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"handle-strip"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"scroll-area"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* scrolls normally */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DraggableSheet&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. &lt;code&gt;&amp;lt;ResizableSplitPane&amp;gt;&lt;/code&gt; — for editor and dashboard layouts
&lt;/h3&gt;

&lt;p&gt;Two or more children, one drag handle between each adjacent pair. Persistence built in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ResizableSplitPane&lt;/span&gt;
  &lt;span class="na"&gt;defaultSizes&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;persistKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"editor-layout"&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FileTree&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Preview&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ResizableSplitPane&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;persistKey&lt;/code&gt; writes the ratios to localStorage. Refresh the page, layout sticks. Double-click any handle to reset to defaults. Drag handles use a 3px threshold and pointer events, same as the rest.&lt;/p&gt;

&lt;p&gt;Custom handles? One render prop, called per boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ResizableSplitPane&lt;/span&gt;
  &lt;span class="na"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isDragging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;orientation&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isDragging&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#6366f1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#e5e7eb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Sidebar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ResizableSplitPane&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The boring stuff that actually matters
&lt;/h2&gt;

&lt;p&gt;This is the part I rarely see in floating-UI libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pointer Events, not three event systems.&lt;/strong&gt; Mouse, touch, and pen go through one code path. No &lt;code&gt;onTouchStart&lt;/code&gt; + &lt;code&gt;onMouseDown&lt;/code&gt; duplication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ResizeObserver&lt;/code&gt; everywhere.&lt;/strong&gt; When your child's size changes — say, a chat widget expands when opened — the wrapper re-clamps to stay on-screen. No more launchers stuck half off the right edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;z-index: 2147483647&lt;/code&gt;.&lt;/strong&gt; Yes, the max. Because if I'm a floating UI library, I'm above your modal. Stop fighting me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tree-shaking actually works.&lt;/strong&gt; Import &lt;code&gt;MovableLauncher&lt;/code&gt; and you get &lt;code&gt;MovableLauncher&lt;/code&gt;. You do not get the sheet, the dock, or the splitter pulled in by accident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript-first.&lt;/strong&gt; All props, all types, all generics exported. &lt;code&gt;Edge&lt;/code&gt;, &lt;code&gt;SnapPoint&lt;/code&gt;, &lt;code&gt;HandleInfo&lt;/code&gt; — pull them in by name.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What it doesn't do (on purpose)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No styling.&lt;/strong&gt; Zero. You bring your background, padding, gap, shadows. The kit gives you data attributes (&lt;code&gt;data-edge&lt;/code&gt;, &lt;code&gt;data-orientation&lt;/code&gt;, &lt;code&gt;data-snap&lt;/code&gt;, &lt;code&gt;data-dragging&lt;/code&gt;) so you can style state without re-rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No context providers.&lt;/strong&gt; Drop a component anywhere, it works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No animation library.&lt;/strong&gt; Transforms and CSS transitions only. The FLIP animation in &lt;code&gt;SnapDock&lt;/code&gt; is hand-rolled in ~30 lines because pulling in Framer Motion to flip a dock would be insane.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No "kitchen sink" component.&lt;/strong&gt; If you want something that's a floating launcher &lt;em&gt;and&lt;/em&gt; a dock &lt;em&gt;and&lt;/em&gt; a sheet, you compose them. They don't know about each other and they don't need to.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When you'd actually reach for this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Building a &lt;strong&gt;chat widget or feedback button&lt;/strong&gt; that users can move out of their way&lt;/li&gt;
&lt;li&gt;Shipping a &lt;strong&gt;floating toolbar&lt;/strong&gt; in a doc/canvas editor&lt;/li&gt;
&lt;li&gt;Building a &lt;strong&gt;mobile detail sheet&lt;/strong&gt; — filters, cart, product details&lt;/li&gt;
&lt;li&gt;Adding an &lt;strong&gt;inspector or debug panel&lt;/strong&gt; to your app&lt;/li&gt;
&lt;li&gt;Replacing your hand-rolled, flexbox-and-&lt;code&gt;mousemove&lt;/code&gt; &lt;strong&gt;resizable sidebar&lt;/strong&gt; with something that handles touch and persists across sessions&lt;/li&gt;
&lt;li&gt;Anything VS Code / Figma / Linear-shaped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need a full design system, this isn't it. If you need a single, well-scoped primitive, this is exactly it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The fastest way to see what it feels like is the &lt;a href="https://react-driftkit.saktichourasia.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;live demo&lt;/strong&gt;&lt;/a&gt; — drag every component around, snap them between edges, resize the panes.&lt;/p&gt;

&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-driftkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/react-driftkit" rel="noopener noreferrer"&gt;react-driftkit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/shakcho/react-drift" rel="noopener noreferrer"&gt;shakcho/react-drift&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://react-driftkit.saktichourasia.dev/" rel="noopener noreferrer"&gt;react-driftkit.saktichourasia.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;This is &lt;strong&gt;v0.4&lt;/strong&gt; and the kit is actively growing. More small, single-purpose floating-UI primitives are on the way — same design rules: tree-shakable, unstyled, one component per job. No bloat, no providers, no design-system lock-in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two things would help a lot:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;⭐ Star the repo on &lt;a href="https://github.com/shakcho/react-drift" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/strong&gt; It's the clearest signal for what to prioritize next, and it helps other devs find the library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open a &lt;a href="https://github.com/shakcho/react-drift/issues" rel="noopener noreferrer"&gt;GitHub issue&lt;/a&gt; with feature requests.&lt;/strong&gt; If there's a floating-UI primitive you keep rebuilding by hand — a draggable modal, a magnetic snap-grid, anything — file an issue. Real use cases drive the roadmap. The next component is whatever the most people are asking for.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bug reports and PRs equally welcome.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this post helped, a star on GitHub, and an issue with what you'd build next all go a long way.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>typescript</category>
      <category>react</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
