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

awesome-product-slider

v0.1.4

Published

A clean glass-morphism product slider for React 19 with orbital card display, auto-play, swipe, and keyboard support.

Downloads

457

Readme

awesome-product-slider

A clean, glass-morphism product slider for React 19. Features a two-column editorial layout with a left text panel and a right orbital card display, an animated SVG arc connecting satellite thumbnails, a central floating hero card, quantity stepper, per-item accent colours, auto-play, swipe, and full keyboard support — with zero UI dependencies.


Installation

npm install awesome-product-slider
yarn add awesome-product-slider
pnpm add awesome-product-slider

Quick Start

Always import the stylesheet alongside the component — it provides all glass-morphism styles, keyframe animations, the two-column layout, and responsive breakpoints.

import AwesomeProductSlider from 'awesome-product-slider'
import 'awesome-product-slider/style.css'

Examples

1. Static Data

Pass a plain JavaScript array directly to the data prop. No network request is made — the slider renders immediately. You can also swap emoji for image and pass an imported image/SVG (see the sample data in src/data.js).

import AwesomeProductSlider from 'awesome-product-slider'
import 'awesome-product-slider/style.css'

const PRODUCTS = [
  {
    id: 1,
    title: 'Acai Power Bowl',
    subtitle: 'Superfood Series',
    price: '$12.99',
    tag: 'BESTSELLER',
    description:
      'Organic acai base topped with fresh blueberries, banana slices, granola, and a drizzle of raw honey. Cold-prepped daily.',
    accent: '#a78bfa',
    bg: 'rgba(167,139,250,0.12)',
    emoji: '🫐',
  },
  {
    id: 2,
    title: 'Green Detox Smoothie',
    subtitle: 'Cleanse Range',
    price: '$8.49',
    tag: 'NEW',
    description:
      'Cold-pressed spinach, cucumber, fresh ginger, lemon juice, and a pinch of Himalayan salt. Zero sugar added.',
    accent: '#34d399',
    bg: 'rgba(52,211,153,0.12)',
    emoji: '🥤',
  },
  {
    id: 3,
    title: 'Mango Chilli Bowl',
    subtitle: 'Tropical Range',
    price: '$11.25',
    tag: 'SPICY',
    description:
      'Ripe Alphonso mango, toasted coconut, micro-chilli flakes, and lime zest on a coconut-milk chia base.',
    accent: '#fb923c',
    bg: 'rgba(251,146,60,0.12)',
    emoji: '🥭',
  },
  {
    id: 4,
    title: 'Cold Brew Coffee',
    subtitle: 'Specialty Coffee',
    price: '$5.75',
    tag: 'DAILY',
    description:
      'Single-origin Colombian beans steeped for 20 hours. Served over ice with oat milk. Naturally low acid.',
    accent: '#d97706',
    bg: 'rgba(217,119,6,0.12)',
    emoji: '☕',
  },
]

export default function App() {
  return (
    <AwesomeProductSlider
      data={PRODUCTS}
      onSlideClick={(item, qty) =>
        console.log(`Added ${qty}× ${item.title} to cart`)
      }
    />
  )
}

2. Local JSON File

Import a .json file directly. The bundler resolves it at build time — no fetch, no loading state.

import AwesomeProductSlider from 'awesome-product-slider'
import 'awesome-product-slider/style.css'

import products from './data/products.json'

export default function App() {
  return (
    <AwesomeProductSlider
      data={products}
      onSlideClick={(item, qty) =>
        alert(`🛒 ${qty}× ${item.title} — ${item.price}`)
      }
    />
  )
}

Your products.json should follow this shape:

[
  {
    "id": 1,
    "title": "Acai Power Bowl",
    "subtitle": "Superfood Series",
    "price": "$12.99",
    "tag": "BESTSELLER",
    "description": "Organic acai base topped with fresh blueberries and granola.",
    "accent": "#a78bfa",
    "bg": "rgba(167,139,250,0.12)",
    "emoji": "🫐"
  },
  {
    "id": 2,
    "title": "Green Detox Smoothie",
    "subtitle": "Cleanse Range",
    "price": "$8.49",
    "tag": "NEW",
    "description": "Cold-pressed spinach, cucumber, ginger and lemon. Zero sugar.",
    "accent": "#34d399",
    "bg": "rgba(52,211,153,0.12)",
    "emoji": "🥤"
  }
]

3. REST API Endpoint

Pass a URL string to data. The component fetches on mount, shows a loading spinner while the request is in flight, and renders automatically on success. The response must be a JSON array or an object with a data array field.

import AwesomeProductSlider from 'awesome-product-slider'
import 'awesome-product-slider/style.css'

export default function App() {
  return (
    <AwesomeProductSlider
      data="https://api.example.com/products/featured"
      onSlideClick={(item, qty) => {
        fetch('/api/cart', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ productId: item.id, quantity: qty }),
        })
      }}
    />
  )
}

The API must return either a flat array:

[
  { "id": 1, "title": "...", "accent": "#a78bfa", "emoji": "🫐", ... }
]

or an envelope object:

{
  "data": [
    { "id": 1, "title": "...", "accent": "#a78bfa", "emoji": "🫐", ... }
  ]
}

Item Shape

Each object in the data array must conform to the following shape.

| Property | Type | Required | Description | |---------------|-------------------|:--------:|-------------| | id | string \| number | ✅ | Unique identifier used as the React key. | | title | string | ✅ | Primary product name shown as the large heading in the left panel. | | emoji | string | ✅ | Single emoji rendered in the central hero card and satellite thumbnail. | | accent | string | ✅ | CSS hex colour applied to the eyebrow tag, price label, satellite ring, CTA button, footer dot, and card glow. | | bg | string | ✅ | CSS colour value used as the background fill for the satellite card and the central hero card (use a low-opacity version of accent, e.g. "rgba(167,139,250,0.12)"). | | subtitle | string | — | Small label shown above the title in the left panel (e.g. category or range name). | | price | string | — | Price string displayed beneath the title (e.g. "$12.99", "From $49/mo"). Any string is accepted. | | tag | string | — | Short badge label shown in the top-right of the hero card and as the eyebrow in the left panel (e.g. "BESTSELLER", "NEW"). | | description | string | — | Body copy shown in the left panel beneath the price. |


Component Props

| Prop | Type | Required | Default | Description | |----------------|-------------------------------------------|:--------:|:-------:|-------------| | data | Item[] \| string | ✅ | — | Either a static array of item objects (or imported JSON), or a URL string pointing to a JSON REST endpoint. When a URL is passed the component fetches on mount, shows a loading spinner, and renders on success. The API must return a JSON array or { data: [] }. | | onSlideClick | (item: Item, qty: number) => void | — | — | Called when the user clicks the Order Now button on the active slide. Receives the full active item object and the current quantity from the stepper. Use this to add to cart, push to a router, fire analytics, and so on. |


Built-In Interactions

| Interaction | Behaviour | |----------------------|-----------| | Auto-play | Advances to the next slide every 4.5 seconds automatically. | | Hover to pause | Auto-play pauses when the cursor enters the component and does not resume until the next mount cycle. | | Satellite click | Clicking any satellite thumbnail in the orbit jumps directly to that slide and pauses auto-play. | | Prev / Next | Clicking the Previous or Next text buttons in the left panel navigates one slide and pauses auto-play. | | Keyboard | ArrowRight advances, ArrowLeft goes back. Both pause auto-play. Handlers are attached to window. | | Quantity stepper | The − and + buttons adjust the quantity (minimum 1). Quantity resets to 1 on every slide change. | | Order Now | Fires onSlideClick(item, qty) and logs the order to the console. | | Loading state | When data is a URL, a centred spinner with the label "Loading menu…" is shown until the fetch resolves. |


Keyboard Navigation

| Key | Action | |--------------|------------------------| | ArrowRight | Jump to next slide | | ArrowLeft | Jump to previous slide |


Responsive Behaviour

On viewports narrower than 860px the two-column grid collapses to a single column, navigation links in the navbar are hidden, and the orbit stage scales down from 500 × 500px to 340 × 340px. The central hero card scales from 220 × 220px to 150 × 150px. No configuration is required.


License

MIT © 2026