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

@thewishlistco/preference-widget

v1.1.3

Published

A JavaScript library for managing customer preferences with The Wishlist API. This widget handles preference logic and API integration while giving developers full control over the UI presentation.

Downloads

13

Readme

🛠️ Preference Widget

A JavaScript library for managing customer preferences with The Wishlist API. This widget handles preference logic and API integration while giving developers full control over the UI presentation.

📦 Installation

Option 1: CDN (Recommended)

<script src="https://unpkg.com/@thewishlistco/preference-widget@latest/script.js"></script>

Option 2: NPM

npm install @thewishlistco/preference-widget
import PreferenceWidget from "@thewishlistco/preference-widget";

Option 3: Download

Download script.js and include it in your project:

<script src="path/to/script.js"></script>

🚀 Quick Start

1. Initialize the Widget

const widget = new PreferenceWidget({
   tenantId: "your-tenant-id",
   customerEmail: "[email protected]",
});

// Initialize (loads preferences structure and customer data)
await widget.init();

2. Get Category Options

// Get brand options
const brands = widget.getCategoryOptions("womens_brands");
console.log(brands);
// Returns: [{ id: 'adidas', value: 'Adidas', selected: true }, ...]

// Get any category
const colors = widget.getCategoryOptions("womens_colors");
const categories = widget.getCategoryOptions("womens_categories");

3. Create Your UI

// Create buttons for each option
brands.forEach((option) => {
   const button = document.createElement("button");
   button.textContent = option.value;
   button.className = option.selected ? "selected" : "";

   // Handle clicks
   button.onclick = async () => {
      await widget.toggleOption("womens_brands", option.id);
      button.classList.toggle("selected");
   };

   container.appendChild(button);
});

⚙️ Configuration

| Parameter | Type | Required | Default | Description | | --------------- | -------- | ---------- | ----------- | ----------------------------------------------------- | | tenantId | string | ✅ Yes | - | Your unique tenant identifier from The Wishlist | | customerEmail | string | No | null | Customer's email address for personalized preferences |

Example

const widget = new PreferenceWidget({
   tenantId: "your-tenant-id",
   customerEmail: "[email protected]",
});

🔧 API Methods

init()

Initialize the widget and load data.

await widget.init();

getCategoryOptions(categoryKey)

Get options for a specific preference category.

const options = widget.getCategoryOptions("womens_brands");
// Returns array of: { id: string, value: string, selected: boolean }
// If no customer email assigned, all options return selected: false

toggleOption(categoryKey, optionId)

Toggle an option selection and save to API.

await widget.toggleOption("womens_brands", "adidas");
// Throws error if no customer email assigned

assignCustomerEmail(customerEmail)

Assign customer email and load their preferences.

await widget.assignCustomerEmail("[email protected]");
// Loads customer data and preferences, enables toggling

📝 Complete Examples

Example 1: With Customer Email (Logged-in User)

<!DOCTYPE html>
<html>
   <head>
      <title>Brand Preferences - Logged In</title>
      <style>
         .option-button {
            padding: 12px 16px;
            border: 2px solid #e1e5e9;
            background: white;
            cursor: pointer;
            margin: 4px;
         }
         .option-button.selected {
            border-color: #007bff;
            background: #f8f9ff;
            color: #007bff;
         }
      </style>
   </head>
   <body>
      <h2>Your Brand Preferences</h2>
      <div id="brands-container"></div>

      <script src="https://unpkg.com/@thewishlistco/preference-widget@latest/script.js"></script>
      <script>
         async function initializePreferences() {
            const widget = new PreferenceWidget({
               tenantId: "your-tenant-id",
               customerEmail: "[email protected]",
            });

            await widget.init();
            renderBrands(widget);
         }

         function renderBrands(widget) {
            const brands = widget.getCategoryOptions("womens_brands");
            const container = document.getElementById("brands-container");
            container.innerHTML = "";

            brands.forEach((brand) => {
               const button = document.createElement("button");
               button.className = `option-button ${brand.selected ? "selected" : ""}`;
               button.textContent = brand.value;

               button.onclick = async () => {
                  try {
                     await widget.toggleOption("womens_brands", brand.id);
                     button.classList.toggle("selected");
                  } catch (error) {
                     alert(error.message);
                  }
               };

               container.appendChild(button);
            });
         }

         initializePreferences().catch(console.error);
      </script>
   </body>
</html>

Example 2: Guest User with Login

<!DOCTYPE html>
<html>
   <head>
      <title>Brand Preferences - Guest to Logged In</title>
      <style>
         .option-button {
            padding: 12px 16px;
            border: 2px solid #e1e5e9;
            background: white;
            cursor: pointer;
            margin: 4px;
         }
         .option-button.selected {
            border-color: #007bff;
            background: #f8f9ff;
            color: #007bff;
         }
         .option-button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
         }
         .login-section {
            margin-bottom: 20px;
            padding: 16px;
            background: #f8f9fa;
            border-radius: 8px;
         }
      </style>
   </head>
   <body>
      <div class="login-section">
         <div id="guest-state">
            <h3>You're browsing as a guest</h3>
            <p>Login to save your preferences</p>
            <input type="email" id="email-input" placeholder="Enter your email" />
            <button onclick="loginUser()">Login</button>
         </div>
         <div id="logged-in-state" style="display: none;">
            <h3>Welcome back!</h3>
            <p>Your preferences are saved automatically.</p>
            <button onclick="logoutUser()">Logout</button>
         </div>
      </div>

      <h2>Brand Preferences</h2>
      <div id="brands-container"></div>

      <script src="https://unpkg.com/@thewishlistco/preference-widget@latest/script.js"></script>
      <script>
         let widget;

         async function initializePreferences() {
            // Initialize without customer email (guest user)
            widget = new PreferenceWidget({
               tenantId: "your-tenant-id",
            });

            await widget.init();
            renderBrands();
         }

         function renderBrands() {
            const brands = widget.getCategoryOptions("womens_brands");
            const container = document.getElementById("brands-container");
            container.innerHTML = "";

            brands.forEach((brand) => {
               const button = document.createElement("button");
               button.className = `option-button ${brand.selected ? "selected" : ""}`;
               button.textContent = brand.value;

               // Disable buttons if no customer email
               button.disabled = !widget.customerEmail;

               button.onclick = async () => {
                  try {
                     await widget.toggleOption("womens_brands", brand.id);
                     button.classList.toggle("selected");
                  } catch (error) {
                     alert(error.message);
                  }
               };

               container.appendChild(button);
            });
         }

         async function loginUser() {
            const email = document.getElementById("email-input").value;
            if (!email) {
               alert("Please enter an email");
               return;
            }

            try {
               await widget.assignCustomerEmail(email);

               // Update UI
               document.getElementById("guest-state").style.display = "none";
               document.getElementById("logged-in-state").style.display = "block";

               // Re-render brands with customer preferences
               renderBrands();
            } catch (error) {
               alert("Login failed: " + error.message);
            }
         }

         function logoutUser() {
            // Reset widget state
            widget.customerEmail = null;
            widget.customerId = null;
            widget.customerPreferences = null;
            widget.preferenceId = null;

            // Update UI
            document.getElementById("guest-state").style.display = "block";
            document.getElementById("logged-in-state").style.display = "none";
            document.getElementById("email-input").value = "";

            // Re-render brands (all unselected and disabled)
            renderBrands();
         }

         initializePreferences().catch(console.error);
      </script>
   </body>
</html>

🔄 Data Flow

Guest User Flow

  1. Initialize widget with tenant only (no customer email)
  2. Authentication happens automatically
  3. Load preference structure from configuration API
  4. Get options with getCategoryOptions() (all return selected: false)
  5. Assign customer email when user logs in with assignCustomerEmail()
  6. Load customer data and existing preferences
  7. Enable toggling and auto-save functionality

Logged-in User Flow

  1. Initialize widget with tenant and customer email
  2. Authentication happens automatically
  3. Load preference structure from configuration API
  4. Load customer data and existing preferences
  5. Filter options by region and availability
  6. Developer creates UI using getCategoryOptions()
  7. Handle user interactions with toggleOption()
  8. Auto-save changes to customer preferences

🛠 Framework Integration

React Example

import { useEffect, useState } from "react";

function BrandPreferences({ tenantId, customerEmail }) {
   const [brands, setBrands] = useState([]);
   const [widget, setWidget] = useState(null);

   useEffect(() => {
      async function initWidget() {
         const preferenceWidget = new PreferenceWidget({
            tenantId,
            customerEmail,
         });

         await preferenceWidget.init();
         const brandOptions = preferenceWidget.getCategoryOptions("womens_brands");

         setWidget(preferenceWidget);
         setBrands(brandOptions);
      }

      initWidget();
   }, [tenantId, customerEmail]);

   const handleToggle = async (brandId) => {
      await widget.toggleOption("womens_brands", brandId);

      // Update local state
      setBrands((prev) => prev.map((brand) => (brand.id === brandId ? { ...brand, selected: !brand.selected } : brand)));
   };

   return (
      <div>
         <h2>Select Your Favorite Brands</h2>
         {brands.map((brand) => (
            <button key={brand.id} className={`brand-button ${brand.selected ? "selected" : ""}`} onClick={() => handleToggle(brand.id)}>
               {brand.value}
            </button>
         ))}
      </div>
   );
}