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

@vexia/vexia-widgets-lib

v1.0.1

Published

A lightweight DOM library for embedding Vexia competition widgets

Readme

Vexia Widgets Library

A lightweight Web/DOM library for embedding Vexia competition widgets in an iframe.

Installation

pnpm add @vexia/vexia-widgets-lib

Usage

NPM/TypeScript

import { createCompetitionIframe } from "@vexia/vexia-widgets-lib";

const container = document.getElementById("vexia-widget");

if (container) {
  createCompetitionIframe(container, "YOUR_COMPETITION_ID");
}

The iframe URL is generated as:

https://vexia-widgets--vexia-widgets.europe-west4.hosted.app/competitions/{competitionId}

Browser Script

<div id="vexia-widget" style="height: 600px"></div>
<script src="https://cdn.jsdelivr.net/npm/@vexia/vexia-widgets-lib@1/dist/browser.min.js"></script>
<script>
  VexiaWidgets.createCompetitionIframe(
    document.getElementById("vexia-widget"),
    "YOUR_COMPETITION_ID"
  );
</script>

API

createCompetitionIframe(target, competitionId, options?)

Creates an iframe and appends it to target.

Parameters:

  • target (HTMLElement) - DOM element that will receive the iframe.
  • competitionId (string) - Competition ID used in the iframe URL.
  • options (CreateCompetitionIframeOptions, optional) - iframe customization.

Options:

  • title - Accessible iframe title. Defaults to "Vexia competition widget".
  • className - CSS class to add to the iframe.
  • height - iframe height. Defaults to "100%".
  • dynamicHeight - update iframe height when a matching postMessage payload is received. Defaults to true.
  • dynamicHeightEventName - message type used for resizing. Defaults to "vexiaWidgetsIframeResizer".
  • width - iframe width. Defaults to "100%".
  • backgroundColor - background color applied to the iframe element. Defaults to "white".
  • fullWidth - make the iframe span the viewport width even inside a narrower parent. Defaults to false.
  • allow - iframe allow policy.
  • allowFullscreen - whether fullscreen is allowed. Defaults to true.

addCompetitionWidget is also exported as an alias of createCompetitionIframe.

Full Width

Use fullWidth: true when the iframe should visually span the viewport even if the target element is inside a centered or narrow parent.

createCompetitionIframe(container, "YOUR_COMPETITION_ID", {
  fullWidth: true
});

This applies viewport-width styles to the iframe. If an ancestor has overflow: hidden, the iframe can still be clipped by that ancestor.

Dynamic Height Message

By default, the library listens for message events from the iframe and only handles messages with type: "vexiaWidgetsIframeResizer".

Add this to the page rendered inside the iframe:

const VEXIA_RESIZE_MESSAGE_TYPE = "vexiaWidgetsIframeResizer";

function sendVexiaHeight() {
  const height = Math.max(
    document.documentElement?.scrollHeight ?? 0,
    document.body?.scrollHeight ?? 0
  );

  window.parent.postMessage(
    {
      type: VEXIA_RESIZE_MESSAGE_TYPE,
      detail: {
        height
      }
    },
    "*"
  );
}

function startVexiaHeightReporter() {
  const root = document.documentElement;

  if (!(root instanceof Node)) {
    return;
  }

  sendVexiaHeight();
  window.addEventListener("load", sendVexiaHeight);
  window.addEventListener("resize", sendVexiaHeight);

  if ("ResizeObserver" in window) {
    new ResizeObserver(sendVexiaHeight).observe(root);
  }

  if (document.body instanceof Node && "MutationObserver" in window) {
    new MutationObserver(sendVexiaHeight).observe(document.body, {
      attributes: true,
      childList: true,
      characterData: true,
      subtree: true
    });
  }
}

if (document.readyState === "loading") {
  window.addEventListener("DOMContentLoaded", startVexiaHeightReporter, {
    once: true
  });
} else {
  startVexiaHeightReporter();
}

The payload must match this shape:

window.parent.postMessage(
  {
    type: "vexiaWidgetsIframeResizer",
    detail: {
      height: 720
    }
  },
  "*"
);

Build

pnpm install
pnpm run build

Example

An Express example is available in examples/express-example.