npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@opengspace/react-hover-panel

v1.0.0

Published

A beautiful, draggable floating panel component for React with smart opacity and smooth animations

Readme

@opengspace/react-hover-panel

A beautiful, draggable floating panel component for React with smart opacity, smooth animations, and modern design.

npm version License: MIT Demo

✨ Features

  • 🎨 Modern Design - Clean, beautiful panel with rounded corners and subtle shadows
  • 🎯 Draggable - Drag the panel freely in both X and Y axes using the iPhone X-style drag bar
  • 👁️ Smart Opacity - Automatically fades when idle, becomes fully visible on hover/drag
  • 📱 Responsive - Adapts to mobile devices with touch support
  • 🎭 Icon Regions - 5 customizable icon regions with tooltips (top-left, top-center, top-right, bottom-left, bottom-right)
  • ⚡ Smooth Animations - GPU-accelerated with 60fps performance using requestAnimationFrame
  • 🔒 Boundary Control - Keeps panel within viewport with configurable edge margins
  • 🎪 Portal Tooltips - Tooltips render outside the panel to prevent event interference
  • ⚙️ Highly Customizable - Extensive props for customization

📦 Installation

npm install @opengspace/react-hover-panel
# or
yarn add @opengspace/react-hover-panel
# or
pnpm add @opengspace/react-hover-panel

🚀 Quick Start

import React from 'react';
import FloatingPanel from '@opengspace/react-hover-panel';

function App() {
  return (
    <FloatingPanel
      width={380}
      onClose={() => console.log('Panel closed')}
      topLeft={{ icon: <span>⌂</span>, tooltip: 'Home' }}
      bottomLeft={{ icon: <span>⚙</span>, tooltip: 'Settings' }}
    >
      <div>
        <h2>Welcome!</h2>
        <p>This is a draggable floating panel.</p>
      </div>
    </FloatingPanel>
  );
}

📖 Props

Layout & Size

| Prop | Type | Default | Description | |------|------|---------|-------------| | width | number \| string | 360 | Width of the panel (px or CSS value) | | topPadding | number | 20 | Top padding from window edge (px) | | bottomPadding | number | 20 | Bottom padding from window edge (px) | | edgeMargin | number | 20 | Minimum distance from window edges (px) |

Dragging & Position

| Prop | Type | Default | Description | |------|------|---------|-------------| | draggable | boolean | true | Enable/disable dragging | | defaultPosition | { x: number, y: number } | undefined | Initial position | | boundary | 'window' \| 'parent' \| 'none' | 'window' | Boundary constraint for dragging |

Opacity & Appearance

| Prop | Type | Default | Description | |------|------|---------|-------------| | idleOpacity | number | 0.7 | Opacity when panel is idle (0-1) | | activeOpacity | number | 1.0 | Opacity when panel is active (0-1) | | opacityTransitionDuration | number | 300 | Transition duration in ms | | roundedCorners | boolean | true | Enable/disable rounded corners | | shadow | boolean | true | Enable/disable shadow | | zIndex | number | 1000 | z-index of the panel |

Icon Regions

Each icon region accepts either:

  • A React element (just the icon)
  • An object { icon: ReactElement, tooltip: string }

| Prop | Type | Default | Description | |------|------|---------|-------------| | topLeft | ReactElement \| { icon: ReactElement, tooltip: string } | - | Icon for top-left corner | | topCenter | ReactElement \| { icon: ReactElement, tooltip: string } | - | Icon for top-center | | topRight | ReactElement \| { icon: ReactElement, tooltip: string } | - | Icon for top-right corner | | bottomLeft | ReactElement \| { icon: ReactElement, tooltip: string } | - | Icon for bottom-left corner | | bottomRight | ReactElement \| { icon: ReactElement, tooltip: string } | - | Icon for bottom-right corner |

Close Button

| Prop | Type | Default | Description | |------|------|---------|-------------| | onClose | () => void | - | Callback when close button is clicked (replaces top-right icon) |

Event Callbacks

| Prop | Type | Default | Description | |------|------|---------|-------------| | onDragStart | () => void | - | Callback when dragging starts | | onDragEnd | (position: { x: number, y: number }) => void | - | Callback when dragging ends | | onVisibilityChange | (isVisible: boolean) => void | - | Callback when visibility changes (hover/drag) |

Other

| Prop | Type | Default | Description | |------|------|---------|-------------| | className | string | '' | Additional CSS class names | | style | CSSProperties | {} | Additional inline styles | | ref | RefObject | - | Forwarded ref |

💡 Usage Examples

Basic Panel with Close Button

<FloatingPanel
  width={400}
  onClose={() => setShowPanel(false)}
>
  <div>
    <h3>Basic Panel</h3>
    <p>Drag the bar at the top to move this panel around!</p>
  </div>
</FloatingPanel>

Panel with Icons and Tooltips

<FloatingPanel
  width={380}
  topLeft={{ icon: <span>🏠</span>, tooltip: 'Home' }}
  topCenter={{ icon: <span>⋯</span>, tooltip: 'Menu' }}
  topRight={{ icon: <span>⋮</span>, tooltip: 'More options' }}
  bottomLeft={{ icon: <span>⚙️</span>, tooltip: 'Settings' }}
  bottomRight={{ icon: <span>ℹ️</span>, tooltip: 'Help' }}
>
  <div>
    <h3>Panel with Icons</h3>
    <p>Hover over the icons to see tooltips!</p>
  </div>
</FloatingPanel>

Panel with Custom Styling

<FloatingPanel
  width={420}
  idleOpacity={0.3}
  activeOpacity={1.0}
  roundedCorners={true}
  shadow={true}
  zIndex={2000}
  className="my-custom-panel"
  style={{ border: '2px solid #667eea' }}
>
  <div>
    <h3>Custom Styled Panel</h3>
    <p>Customize opacity, corners, shadows, and more!</p>
  </div>
</FloatingPanel>

Panel with Event Handlers

const handleDragStart = () => {
  console.log('Drag started');
};

const handleDragEnd = (position) => {
  console.log('Drag ended at:', position);
};

const handleVisibilityChange = (isVisible) => {
  console.log('Panel is', isVisible ? 'visible' : 'idle');
};

<FloatingPanel
  width={380}
  onDragStart={handleDragStart}
  onDragEnd={handleDragEnd}
  onVisibilityChange={handleVisibilityChange}
>
  <div>
    <h3>Panel with Events</h3>
    <p>Check the console for event logs!</p>
  </div>
</FloatingPanel>

Panel with Custom Content

<FloatingPanel
  width={400}
  topLeft={{ icon: <span>👤</span>, tooltip: 'Profile' }}
  onClose={() => setShowPanel(false)}
>
  <div>
    <h2 style={{ margin: '0 0 16px 0' }}>User Profile</h2>

    <input
      type="text"
      placeholder="Username"
      style={{
        width: '100%',
        padding: '10px',
        marginBottom: '12px',
        border: '1px solid #ddd',
        borderRadius: '8px'
      }}
    />

    <textarea
      placeholder="Bio"
      style={{
        width: '100%',
        padding: '10px',
        border: '1px solid #ddd',
        borderRadius: '8px',
        minHeight: '100px'
      }}
    />

    <button
      style={{
        width: '100%',
        padding: '12px',
        background: '#667eea',
        color: 'white',
        border: 'none',
        borderRadius: '8px',
        cursor: 'pointer',
        marginTop: '12px'
      }}
    >
      Save
    </button>
  </div>
</FloatingPanel>

🎨 Customization

CSS Classes

The component uses the following CSS classes that you can override:

  • .floating-panel - Main panel container
  • .floating-panel-header - Header area with drag bar
  • .floating-panel-main - Main content area (scrollable)
  • .floating-panel-footer - Footer area
  • .drag-bar - iPhone X-style drag bar
  • .panel-icon - Icon containers
  • .tooltip - Tooltip elements

Example Custom Styles

/* Override drag bar color */
.floating-panel .drag-bar {
  background: rgba(102, 126, 234, 0.3);
}

/* Custom panel background */
.floating-panel {
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}

/* Custom scrollbar */
.floating-panel-main::-webkit-scrollbar {
  width: 8px;
}

.floating-panel-main::-webkit-scrollbar-thumb {
  background: #667eea;
  border-radius: 4px;
}

🌐 Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)
  • Mobile browsers (iOS Safari, Chrome Mobile)

📝 License

MIT © opengspace

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📧 Support

For issues and questions, please visit our GitHub Issues.

🔗 Links

🚀 Automatic Deployment

This project uses GitHub Actions to automatically deploy the demo to GitHub Pages on every push to the main branch. See DEPLOYMENT.md for details.


Made with ❤️ by opengspace