@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.
Maintainers
Keywords
Readme
Accessibility Panel for Low-Vision and Visually Impaired Users
@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
localStoragefor 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-panelAdd 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-cfgfor DOM configuration anddata-js-vipanel-togglefor external toggle controls. - Initialize the imperative
ViPanelAPI only in a browser environment. - State is persisted in
localStorageusing stable keys:viSettings,viIsOpened, andviIsShouldUtterControls. - The module assigns the active singleton
ViPanelModeltowindow.ViPanel; usewindow.ViPanel.stateor theonReadyargument 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
