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

@delement/vi-panel

v0.4.3

Published

TypeScript accessibility panel and low-vision widget for websites: visually impaired mode, contrast controls, font settings, speech synthesis, and voice commands.

Readme

Accessibility Panel for Low-Vision and Visually Impaired Users

npm version npm downloads license TypeScript React

@delement/vi-panel is a React 19 and TypeScript accessibility widget that adds a low-vision mode, also known as a visually impaired version, to websites and web applications. The package provides an accessible control panel for font size, font family, line spacing, color contrast, image visibility, speech synthesis, page reading, and voice commands.

Use it when you need a configurable website accessibility panel, a WCAG-oriented low-vision toolbar, or a ready-made visually impaired mode for an existing frontend without rebuilding the whole design system.

Accessibility Widget Features

  • Low-vision and visually impaired mode for websites, portals, and web applications.
  • Accessibility controls for font size, font family, letter spacing, line height, color contrast, monochrome mode, and image visibility.
  • Speech synthesis for panel controls and full-page reading with browser Web Speech APIs.
  • Voice command support when speech recognition is available in the browser.
  • Persistent user settings in localStorage for repeat visits.
  • External open and close triggers through data-js-vipanel-toggle.
  • Optional floating accessibility button rendered automatically by the package.
  • Configurable style scope, ignored elements, hidden elements, captcha exclusions, and page reading areas.
  • Stateful React 19 runtime mounted into an isolated root while preserving an imperative integration API.
  • TypeScript declarations for public configuration, panel state, and event payloads.

Install Accessibility Panel

npm i @delement/vi-panel
# or
yarn add @delement/vi-panel
# or
pnpm add @delement/vi-panel

Add Low-Vision Mode

import { ViPanel } from "@delement/vi-panel";

new ViPanel();
<button data-js-vipanel-toggle>
  Low-vision version
</button>

ViPanel waits for DOM readiness. It then prepends a host element to document.body and mounts the stateful React runtime with createRoot. The underlying ViPanelModel is a singleton, and that active model is exposed as window.ViPanel.

Server-side rendering

The package can be imported in an SSR environment. If window or document is unavailable, new ViPanel(config) is a silent no-op: it leaves viPanelModel as null, does not invoke onReady or onError, and does not render server markup. Create the panel again from a client-only lifecycle after the DOM exists:

if (typeof window !== "undefined" && typeof document !== "undefined") {
  new ViPanel(config);
}

Configure the Visually Impaired Mode

import { ViPanel } from "@delement/vi-panel";
import type { IViPanelConfig } from "@delement/vi-panel";

const config: IViPanelConfig = {
  /**
   * Media query that disables or closes the accessibility panel while it matches.
   * Defaults to `(max-width: 359px)`, so the panel is available from 360 CSS px.
   * Pass an empty string explicitly to disable the viewport cutoff.
   */
  visibleUntil: "(max-width: 359px)",
  /**
   * Areas where low-vision styles are applied.
   */
  targetSelectors: [ "body" ],
  /**
   * Keeps the panel fixed while the page scrolls.
   */
  isFixed: true,
  /**
   * Content areas used by the "Read page" action.
   */
  pageUtterSelectors: [ "main" ],
  /**
   * Elements hidden while low-vision mode is open.
   */
  hiddenElementsSelectors: [ ".site-banner" ],
  /**
   * Elements excluded from panel styling.
   */
  ignoreElementsSelectors: [ ".map-widget" ],
  /**
   * Captcha selectors handled the same way as ignored elements.
   */
  captchaElementsSelectors: [ "[class*='captcha']" ],
  /**
   * Values used by the font-size accessibility controls.
   */
  fontSizeSettings: {
    fontSizeSmall: "14px",
    fontSizeStandard: "default",
    fontSizeLarge: "20px",
  },
  /**
   * Initial CSS variable values applied on first open and reset.
   * Use "default" to clear a panel-controlled value.
   */
  defaultSettings: {
    deViBaseFontSize: "default",
    deViBaseFontFamily: "sans-serif",
    deViBaseLetterSpacing: "default",
    deViBaseLineHeight: "1.5",
    deViBaseBgColor: "default",
    deViBaseFontColor: "default",
    deViFilter: "default",
    deViImagesDisplay: "default",
  },
  /**
   * Enables speech synthesis for accessibility panel control labels.
   */
  isShouldUtterControls: true,
  /**
   * Query parameter that opens the panel automatically.
   */
  openPanelQueryParam: "openVI",
  /**
   * Settings for the auto-rendered accessibility toggle button.
   */
  autoAddBtnCfg: {
    /**
     * Enables auto-rendering of the toggle button.
     */
    isEnabled: true,
    /**
     * Horizontal side of the viewport.
     */
    side: "right",
    /**
     * Vertical position of the toggle button.
     */
    position: {
      top: "auto",
      bottom: "32px",
    },
    /**
     * Label used while the visually impaired mode is closed.
     */
    openText: "Low-vision version",
    /**
     * Label used while the visually impaired mode is open.
     */
    closeText: "Standard version",
  },
  /**
   * Additional languages and overrides for built-in panel translations.
   * Translation array positions must match langKeys.
   */
  localisation: {
    langKeys: [ "ru", "en", "de" ],
    locales: {
      viPanel: {
        readPage: [ "Озвучить всё", "Read the page", "Seite vorlesen" ],
      },
    },
  },
  /**
   * Runs after the React runtime has mounted.
   */
  onReady: (panel) => {
    console.debug(panel.state.isOpened);
  },
  /**
   * Receives initialization, rendering, recovery, and localization errors.
   */
  onError: (error) => {
    console.error(error);
  },
};

new ViPanel(config);

The auto-rendered button receives the public class deViPanelToggleBtn for external styling.

DOM Configuration for Accessibility Settings

The package can read accessibility configuration from data-js-vipanel-cfg on body. Configuration precedence is package defaults, DOM configuration, then the constructor object. Arrays are replaced rather than concatenated.

<body data-js-vipanel-cfg='{"visibleUntil":"(max-width: 480px)"}'>

Accessibility Panel Events

The panel emits viPanel::isInteracted on both open and close. Use this event to integrate the low-vision mode with analytics, layout state, or custom application logic.

import type { IViPanelInteractedEventDetail } from "@delement/vi-panel";

document.documentElement.addEventListener("viPanel::isInteracted", (event) => {
  const detail = (event as CustomEvent<IViPanelInteractedEventDetail>).detail;

  console.debug(detail.isOpened, detail.settings, detail.isShouldUtterControls);
});

The event detail shape is:

interface IViPanelInteractedEventDetail {
  isOpened: boolean;
  settings: Record<string, string>;
  isShouldUtterControls: boolean;
}

The image-off control visually suppresses img elements that already have an author-provided alt and every SVG <image> element in scope. Meaningful alt text is shown next to an HTML image; decorative alt="" remains decorative. Images without alt, CAPTCHA and ignored content, SVG vector shapes, canvas, frames, objects, and CSS backgrounds are left visible for the site owner to review. Containing <svg> elements stay in the DOM and accessibility tree. Closing or resetting the panel restores the original DOM classes and removes generated visual alternatives.

TypeScript Exports

Public TypeScript types are exported under the names shown below.

import type {
  IDefaultSettings,
  IFontSizeSettings,
  IViPanelAutoAddBtnCfg,
  IViPanelConfig,
  IViPanelInteractedEventDetail,
  IViPanelLocalisationConfig,
  IViPanelState,
  TToggleSide,
  TViPanelLocaleSource,
} from "@delement/vi-panel";

The package entry also exports ViPanel as the primary runtime API.

Runtime Notes

  • React manages panel state, controls, speech UI, voice activation, and effect cleanup.
  • Use data-js-vipanel-cfg for DOM configuration and data-js-vipanel-toggle for external toggle controls.
  • Initialize the imperative ViPanel API only in a browser environment.
  • State is persisted in localStorage using stable keys: viSettings, viIsOpened, and viIsShouldUtterControls.
  • The module assigns the active singleton ViPanelModel to window.ViPanel; use window.ViPanel.state or the onReady argument for the current public state.
  • Voice recognition and speech synthesis depend on browser support and user permissions.

Documentation

Full accessibility panel documentation and examples are available on the D-Element UI portal in the ecosystem section: https://ui.d-element.ru