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

@jampolls/sdk

v1.2.0

Published

Official JavaScript SDK for embedding Jampolls interactive polls on any website

Readme

Jampolls SDK

The official JavaScript SDK for embedding Jampolls interactive polls on any website.

npm License


Installation

CDN (no build step required)

<script src="https://cdn.jampolls.com/latest/jampolls.min.js"></script>

Pin to a specific version in production:

<script src="https://cdn.jampolls.com/v1.0.0/jampolls.min.js"></script>

npm

npm install @jampolls/sdk

Get your embed key

  1. Sign in at jampolls.com
  2. Create a poll and set it as active in your dashboard → Widgets
  3. Copy your embed key

Usage

Script tag (plain HTML)

<script src="https://cdn.jampolls.com/latest/jampolls.min.js"></script>

<div id="my-poll"></div>

<script>
  JamPolls.embed('YOUR_EMBED_KEY', '#my-poll');
</script>

Auto-embed via data attribute

No JavaScript needed — just add the attribute and the SDK initialises it automatically:

<script src="https://cdn.jampolls.com/latest/jampolls.min.js"></script>

<div data-jampolls="YOUR_EMBED_KEY"></div>

React

import { JampollsWidget } from '@jampolls/sdk/react';

export default function Page() {
  return (
    <JampollsWidget
      embedKey="YOUR_EMBED_KEY"
      theme="dark"
      vars={{ '--jp-primary': '#7c3aed', '--jp-radius': '12px', 'max-width': '480px' }}
      onVote={({ optionId, removed }) => console.log(optionId, removed)}
    />
  );
}

Vue 3

<script setup>
import { JampollsWidget } from '@jampolls/sdk/vue';

const vars = {
  '--jp-primary': '#7c3aed',
  '--jp-radius': '12px',
  'max-width': '480px',
};
</script>

<template>
  <JampollsWidget embed-key="YOUR_EMBED_KEY" theme="auto" :vars="vars" @vote="onVote" />
</template>

Options

JamPolls.embed('YOUR_EMBED_KEY', '#container', {
  theme: 'dark',       // override the poll owner's theme setting
  vars: {              // override any CSS custom property
    '--jp-primary': '#7c3aed',
    '--jp-radius':  '4px',
    'max-width':    '100%',
  },
  apiUrl: 'http://localhost:8000', // optional, local development only
  onLoad:  (data)  => console.log(data),
  onVote:  (event) => console.log(event.optionId, event.removed),
  onError: (err)   => console.error(err),
});

| Option | Type | Description | |---|---|---| | theme | 'auto' \| 'light' \| 'dark' \| 'jampolls' | Overrides the poll owner's dashboard theme. auto follows the visitor's system preference. | | vars | Record<string, string> | CSS custom property overrides applied directly to the widget. Use this to match your brand. | | apiUrl | string | API origin override for local development. Defaults to https://hub.jampolls.com. | | onLoad | (data: PollData) => void | Fired when poll data loads successfully. | | onVote | (event: VoteEvent) => void | Fired after a vote is submitted or removed. | | onError | (error: Error) => void | Fired on network or API errors. |

Note: show_results, show_branding, and allow_multiple_votes are controlled by the poll owner from their Jampolls dashboard — they are not developer options. Your subscription tier determines what the owner can configure.


CSS customisation

The widget uses CSS custom properties scoped to .jp-widget. Override them via the vars option or in your own stylesheet:

.jp-widget {
  --jp-primary:     #7c3aed; /* accent colour */
  --jp-bg:          #ffffff;
  --jp-surface:     #f8fafc;
  --jp-text:        #0f172a;
  --jp-text-muted:  #64748b;
  --jp-border:      #e2e8f0;
  --jp-radius:      12px;    /* widget corner radius */
  --jp-option-radius: 8px;   /* option button corner radius */
  max-width:        480px;   /* widget width cap */
}

The widget fills its container at width: 100% up to max-width. Control the width by sizing the container or overriding max-width via vars.


API reference

JamPolls.embed(embedKey, target, opts?)

Mounts a poll widget into a container. Returns a widget instance.

  • embedKey — your embed key from the Jampolls dashboard
  • target — CSS selector string or HTMLElement
  • opts — optional configuration (see Options above)

JamPolls.getWidget(target)

Returns the widget instance currently mounted in a container, or null.

JamPolls.removeWidget(target)

Destroys the widget and clears the container.

JamPolls.autoEmbed()

Scans the page for [data-jampolls] elements and initialises them. Called automatically on DOMContentLoaded when using the CDN script.

Widget instance

const widget = JamPolls.embed('KEY', '#container');

widget.refresh(); // re-fetch and re-render
widget.destroy(); // unmount and clear

TypeScript

Full type definitions are included:

import JamPolls, { WidgetOptions, PollData, VoteEvent } from '@jampolls/sdk';

Real-time updates (SSE)

Once a widget loads, it connects to a Server-Sent Events stream for the embed. Vote counts and results update automatically in the background — no page refresh needed.

  • Initial snapshot — on connect, the stream immediately delivers the current poll state
  • Live updates — every vote from any source pushes a poll.update event; the widget re-renders in place
  • Auto-reconnect — if the stream drops, the SDK reconnects using exponential backoff (1 s → 60 s, ±20% jitter)
  • Idle tab — the stream disconnects when the tab is hidden and reconnects when the visitor returns, to avoid unnecessary server load

Offline cache and stale-data indicator

The SDK caches poll state in localStorage (key: jampolls_embed_{embedKey}) after every successful fetch or live update.

When the server is unreachable on load, the SDK renders from cache immediately so visitors still see poll content. A small muted "Last synced X ago" notice appears at the bottom of the widget to indicate the data may be slightly out of date. It disappears as soon as a fresh update arrives.

localStorage key: jampolls_embed_<embedKey>
value shape:      { data: {...}, lastFetchedAt: "<ISO8601 timestamp>" }

The cache is stored per embed key and is never shared across different embeds. Visitors in private/incognito mode get an ephemeral (in-memory) experience with no cache fallback.


Browser support

Chrome 60+, Firefox 55+, Safari 12+, Edge 79+. No IE11.


License

MIT — see LICENSE