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

ngarsa-widget

v1.0.0

Published

Lightweight, customizable floating WhatsApp chat widget for websites and webapps.

Readme

ngarsa-widget

A lightweight, zero-dependency, fully customizable floating WhatsApp chat widget for modern web applications and websites. Written in TypeScript and ready for Bun, Node.js (npm, pnpm, yarn), frontend frameworks (React, Next.js, Vue, Nuxt, Svelte, Astro), and vanilla HTML script tags.

npm version License: MIT Bundle Size TypeScript


Features

  • ⚡ Zero External Dependencies: Self-contained inline SVGs and CSS isolation (~14 KB minified).
  • 🎨 Dynamic Avatar Generator: Automatically generates high-contrast SVG avatars with initials based on brand color and business name.
  • 💬 Flexible Trigger Icons: Use the official WhatsApp vector icon or sync with your brand avatar / logo image.
  • ♿ Accessible by Design: WCAG compliant with keyboard navigation (Escape to close, Enter to send), focus trap, and ARIA labels.
  • 📦 Universal Module Formats: ESM (import), CommonJS (require), TypeScript types (.d.ts), and browser IIFE (<script>).
  • 🔄 Hot Reconfiguration: Update theme, copy, position, or assets on the fly via .updateOptions() without re-mounting.

Quickstart

Installation

Choose your preferred package manager:

# Bun
bun add ngarsa-widget

# npm
npm install ngarsa-widget

# pnpm
pnpm add ngarsa-widget

# yarn
yarn add ngarsa-widget

Implementation Examples

1. Vanilla JavaScript / TypeScript

import { createNgarsaWidget } from "ngarsa-widget";

const widget = createNgarsaWidget({
  phoneNumber: "6281234567890", // International format without '+'
  copy: {
    name: "Customer Support",
    statusText: "Typically replies in minutes",
    welcomeText: "Hi there! How can we help you today?",
    inputPlaceholder: "Type your message..."
  },
  theme: {
    primaryColor: "#01472e", // Forest green
    position: "bottom-right"
  }
});

// Programmatic controls:
// widget.open();
// widget.close();
// widget.toggle();
// widget.updateOptions({ copy: { name: "Live Support" } });
// widget.destroy();

2. React / Next.js (App Router & Pages Router)

"use client";

import { useEffect } from "react";
import { createNgarsaWidget } from "ngarsa-widget";

export default function WhatsAppButton() {
  useEffect(() => {
    const widget = createNgarsaWidget({
      phoneNumber: "6281234567890",
      copy: {
        name: "Acme Support",
        welcomeText: "Welcome to Acme! Need any assistance?"
      },
      theme: {
        primaryColor: "#01472e",
        position: "bottom-right"
      }
    });

    // Clean up when unmounting
    return () => {
      widget.destroy();
    };
  }, []);

  return null;
}

3. Vue 3 / Nuxt 3

<script setup lang="ts">
import { onMounted, onUnmounted } from "vue";
import { createNgarsaWidget, type NgarsaWidgetInstance } from "ngarsa-widget";

let widget: NgarsaWidgetInstance | null = null;

onMounted(() => {
  widget = createNgarsaWidget({
    phoneNumber: "6281234567890",
    copy: {
      name: "Support Desk",
      welcomeText: "How can our engineers help you today?"
    },
    theme: {
      primaryColor: "#01472e"
    }
  });
});

onUnmounted(() => {
  if (widget) {
    widget.destroy();
  }
});
</script>

<template>
  <!-- Widget mounts automatically to document.body -->
</template>

4. Svelte / SvelteKit

<script lang="ts">
  import { onMount, onDestroy } from "svelte";
  import { createNgarsaWidget, type NgarsaWidgetInstance } from "ngarsa-widget";

  let widget: NgarsaWidgetInstance;

  onMount(() => {
    widget = createNgarsaWidget({
      phoneNumber: "6281234567890",
      theme: { primaryColor: "#01472e" }
    });
  });

  onDestroy(() => {
    widget?.destroy();
  });
</script>

5. Plain HTML / Static Websites (CDN Script Tag)

Add the script before the closing </body> tag:

<script src="https://unpkg.com/ngarsa-widget/dist/index.global.js"></script>
<script>
  const widget = NgarsaWidget.createNgarsaWidget({
    phoneNumber: "6281234567890",
    copy: {
      name: "Ngarsa Official",
      welcomeText: "Hi there! How can we help you?"
    },
    theme: {
      primaryColor: "#01472e"
    }
  });
</script>

Automatic Mounting via Script Data Attributes:

<script
  src="https://unpkg.com/ngarsa-widget/dist/index.global.js"
  data-phone="6281234567890"
  data-name="Ngarsa Support"
  data-text="Hello! How can we help?"
  data-color="#01472e"
  defer
></script>

Dynamic Avatar Generator

ngarsa-widget includes a built-in SVG avatar generator that extracts initials and creates an optimized SVG data URI matching your primary brand color:

import { generateAvatar } from "ngarsa-widget";

// Returns data:image/svg+xml;base64,... with "JD" initials on #01472e background
const avatarUri = generateAvatar("John Doe", "#01472e", "#fefae0");

API Reference

NgarsaWidgetOptions

| Property | Type | Default | Description | |---|---|---|---| | phoneNumber | string | (Required) | Destination WhatsApp number (international digits, e.g. "6281234567890"). | | theme | NgarsaTheme | (See below) | Colors, font family, z-index, and screen placement. | | copy | NgarsaCopy | (See below) | Titles, greetings, placeholders, and ARIA accessibility labels. | | assets | NgarsaAssets | (See below) | Custom avatar image, bubble trigger logo, or background pattern. | | defaultOpen | boolean | false | When true, automatically opens the chat panel upon initial render. | | onOpen | () => void | undefined | Callback fired when the chat window opens. | | onClose | () => void | undefined | Callback fired when the chat window closes. | | onSend | (message: string) => void | undefined | Callback fired when user clicks send or presses Enter. |


NgarsaTheme

interface NgarsaTheme {
  primaryColor?: string;          // Default: "#095e54"
  primaryTextColor?: string;      // Default: "#ffffff"
  bubbleColor?: string;           // Default: "#ffffff"
  bubbleIconColor?: string;       // Default: "#4fce5d"
  onlineBadgeColor?: string;      // Default: "#4ad504"
  backgroundColor?: string;       // Default: "#ffffff"
  chatBubbleBackground?: string;  // Default: "#ffffff"
  chatBubbleTextColor?: string;   // Default: "#111111"
  fontFamily?: string;            // System font stack
  zIndex?: number;                // Default: 999999
  position?: "bottom-right" | "bottom-left"; // Default: "bottom-right"
  offsetBottom?: string;          // Default: "20px"
  offsetSide?: string;            // Default: "20px"
}

NgarsaCopy

interface NgarsaCopy {
  name?: string;                 // Default: "Ngarsa Official"
  statusText?: string;           // Default: "Typically replies within a day"
  welcomeText?: string;          // Default: "Hi there 👋, how can we help you?"
  inputPlaceholder?: string;     // Default: "Type a message..."
  sendButtonAriaLabel?: string;  // Default: "Send message to WhatsApp"
  closeButtonAriaLabel?: string; // Default: "Close WhatsApp chat widget"
  openButtonAriaLabel?: string;  // Default: "Open WhatsApp chat"
}

NgarsaAssets

interface NgarsaAssets {
  avatarUrl?: string;             // Custom URL, or leave blank to auto-generate
  hideAvatar?: boolean;          // Default: false
  bubbleIconUrl?: string;        // Custom toggle trigger icon URL (default: WhatsApp SVG)
  backgroundPatternUrl?: string; // Custom chat body pattern URL (default: subtle SVG pattern)
  hideBackgroundPattern?: boolean; // Default: false
}

NgarsaWidgetInstance Methods

const widget = createNgarsaWidget({ phoneNumber: "6281234567890" });

widget.open();                          // Open chat panel
widget.close();                         // Close chat panel
widget.toggle();                        // Toggle open/close state
widget.isOpen();                        // Returns boolean
widget.updateOptions({ copy: { ... } }); // Reconfigure options without unmounting
widget.getElement();                    // Returns widget root HTMLElement
widget.destroy();                       // Removes event listeners & DOM elements

Local Development & Showcase

To run the interactive Forest & Sage demo showcase:

# 1. Install dependencies
pnpm install # or bun install

# 2. Run unit tests
pnpm test

# 3. Build package distributions
pnpm run build

# 4. Launch demo playground
pnpm run demo
# Then visit: http://localhost:3000

Authors & Maintainers

  • Ngarsa — Studio & Digital Craft
  • Risyandi — Engineering & Software Architecture

License

MIT © 2026 Ngarsa