IndiaCN UI

Accessibility Widget

Floating panel of reading adjustments that apply to the whole document and persist.

Introduction

UX4G ships an accessibility panel because Indian public services must serve everyone, and a citizen who needs larger text should not have to know how to change a browser setting to get it.

This is the component that most justifies the library existing. Every adjustment applies to the whole document, not just the components on the page, and is remembered across navigation.

Installation

npx shadcn@latest add https://indiacn.in/r/accessibility-widget.json
import { AccessibilityWidget } from '@/components/ui/accessibility-widget';

Usage

Render it once, near the root of your app. It fixes itself to the bottom-right corner.

<AccessibilityWidget />

It is running on this site

Look in the bottom-right corner. That is this component, mounted in the root layout — the adjustments apply to the page you are reading, and they persist as you move around the docs.

If a control here does not work for you, that is a bug worth reporting, not a demo limitation.

Example

The widget below is scoped to its container so it does not follow you around the docs. In your app it is fixed to the viewport.

Apply for a ration card

Adjust text size, spacing and contrast from the button in the corner. Settings apply to the whole page and are remembered.

Read the eligibility criteria before you begin.

AccessibilityWidgetDefault
'use client';

import { AccessibilityWidget } from '@/components/ui/accessibility-widget';
import { Body1, Headline5 } from '@/components/ui/typography';

export default function Component() {
  return (
    <div className='relative h-[420px] w-full overflow-hidden rounded-md border border-neutral-100'>
      <div className='flex flex-col gap-3 p-6'>
        <Headline5>Apply for a ration card</Headline5>
        <Body1 className='max-w-[420px] text-neutral-600'>
          Adjust text size, spacing and contrast from the button in the corner. Settings apply to
          the whole page and are remembered.
        </Body1>
        <Body1>
          Read the{' '}
          <a href='#eligibility' className='text-primary underline'>
            eligibility criteria
          </a>{' '}
          before you begin.
        </Body1>
      </div>
      <AccessibilityWidget className='absolute right-4 bottom-4' />
    </div>
  );
}

What each setting does

SettingEffect
Increase text sizeRoot font size, in three steps of 12.5%. Everything sized in rem scales with it
Increase line heightRoot line height, up to 2.25
Increase text spacingLetter spacing, up to 0.15em
Highlight linksUnderline plus a visible outline on every link
Dyslexia friendlySwitches to a hyperlegible font stack and loosens tracking
Hide imagesHides images, video and decorative SVG, leaving the text
Invert coloursInverts the page, re-inverting media so photographs stay readable
Reading maskA band that follows the pointer and dims the rest of the page

Steps cycle: pressing a + three times and once more returns it to normal, so there is always a way back without hunting for Reset.

Why there is no "Screen Reader" row

UX4G's panel lists one. This does not ship it.

A button labelled "Screen Reader" that reads the page with the browser's speech API is not a screen reader — it has no navigation, no landmark support, no forms mode, and no braille output. Offering one tells a sighted product owner the box is ticked while giving a blind visitor something markedly worse than the software they already use.

If you have a real integration, pass it in:

<AccessibilityWidget extraRows={<MyScreenReaderRow />} />

Notes

  • Settings are stored under indiacn-accessibility in localStorage. Blocked storage is handled — the settings simply do not persist.
  • State lives in a module store read through useSyncExternalStore, so two widgets on one page cannot disagree, and the server render always starts from the defaults.
  • The panel closes on Escape.
  • The behaviour stylesheet is injected by the component, so installing through the registry brings the behaviour with it.

API Reference

AccessibilityWidget

PropTypeDefaultDescription
titlestring'Accessibility options'Panel heading and the button's accessible name
extraRowsReactNodeRows appended before the footer
classNamestringOverrides the fixed positioning

On this page