A lightweight, accessible React component for creating draggable buttons with smooth animations and touch support.
- 🖱️ Smooth drag interactions
 - 📱 Touch device support
 - ♿ Accessibility focused
 - 🎨 Customizable styling
 - 🔄 Position tracking
 - 🚫 Disabled state support
 
npm install drag-button
# or
yarn add drag-buttonimport { DragButton } from 'drag-button';
function App() {
  const handleDragStart = (event, { offsetX, offsetY }) => {
    console.log('Drag started at:', offsetX, offsetY);
  };
  const handleDrag = (event, { x, y }) => {
    console.log('Dragging at:', x, y);
  };
  const handleDragEnd = (event) => {
    console.log('Drag ended');
  };
  return (
    <DragButton
      onDragStart={handleDragStart}
      onDrag={handleDrag}
      onDragEnd={handleDragEnd}
    >
      Drag me!
    </DragButton>
  );
}| Prop | Type | Default | Description | 
|---|---|---|---|
children | 
node | 
Required | Content to be rendered inside the button | 
onDragStart | 
function | 
undefined | 
Called when drag starts | 
onDrag | 
function | 
undefined | 
Called while dragging | 
onDragEnd | 
function | 
undefined | 
Called when drag ends | 
className | 
string | 
'' | 
Additional CSS classes | 
disabled | 
boolean | 
false | 
Disables the drag functionality | 
The component comes with default styles but can be customized using the className prop:
<DragButton className="custom-button">
  Custom Styled Button
</DragButton>The component automatically handles touch events for mobile devices. No additional configuration needed!
- Proper focus management
 - Keyboard navigation support
 - ARIA attributes
 - High contrast mode support
 
import { DragButton } from 'drag-button';
import { useState } from 'react';
function PositionTracker() {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  return (
    <div>
      <DragButton
        onDrag={(event, pos) => setPosition(pos)}
        style={{ marginBottom: '20px' }}
      >
        Drag me and watch the position
      </DragButton>
      <div>
        Current position: X: {Math.round(position.x)}, Y: {Math.round(position.y)}
      </div>
    </div>
  );
}To explore the component interactively and view all examples:
npm run storybookThen visit http://localhost:6006 in your browser.
To stop the Storybook server:
- Method 1: Press 
Ctrl + Cin the terminal window where Storybook is running- When prompted "Terminate batch job (Y/N)?", type 
Yand press Enter 
 - When prompted "Terminate batch job (Y/N)?", type 
 - Method 2: Using TaskKill (if the process is stuck or Method 1 doesn't work)
# Find the process using port 6006 netstat -ano | findstr :6006 # Look for the PID in the LISTENING state (usually the first entry) # Kill that process (replace XXXX with the PID) taskkill /PID XXXX /F
 
- Default: Basic DragButton implementation with standard functionality
 - Disabled: Example of the button in a disabled state
 - CustomStyle: Demonstration of custom styling options
 - WithPositionTracking: Interactive example showing real-time position tracking
 
- Create stories in 
src/storiesdirectory - Follow the naming convention: 
ComponentName.stories.jsx - Use the template pattern for consistent story creation:
 
import React from 'react';
import { fn } from '@storybook/test';
import DragButton from '../../src/components/DragButton';
export default {
  title: 'Components/DragButton',
  component: DragButton,
  argTypes: {
    // Define your props here
  },
};
const Template = (args) => <DragButton {...args} />;
export const YourStory = Template.bind({});
YourStory.args = {
  // Define your story props here
};- Document all props using 
argTypes - Include examples of common use cases
 - Add interactive examples for complex features
 - Use actions to demonstrate event handling
 - Include accessibility information in the docs
 
Contributions are welcome! Please feel free to submit a Pull Request.
MIT © Mark Castle