Accessibility
This guide says what Osirion.Blazor components do for keyboard and screen reader users, shows how to check a site that uses them, and lists what the library cannot do for you. It is for developers who ship a site built with the components and want to know where their own work starts.
The library does not claim conformance with WCAG or any other standard. It states what the code does and which checks the repository runs; whether your pages conform depends on your content and your own styles.
Before you start
- A running site that uses Osirion.Blazor 4.1.0 or later. Getting started builds one.
- A desktop browser. A screen reader is useful for the screen reader pass: NVDA on Windows, VoiceOver on macOS.
- Node.js, only if you want the command line checker in Run an automated checker.
Know what the components do
This is what the code of the 4.1.0 release does. Each row names the component, so you can read its page.
| Area | What it does | Component |
|---|---|---|
| Skip link | A link to the main content is the first focusable element. It is off screen until it gets focus. ShowSkipLink (default true), SkipLinkText (default "Skip to main content") and MainContentId (default osirion-main-content) configure it. |
OsirionPageLayout |
| Landmarks | The layout always renders main, and renders header and footer when you fill the Header and Footer slots. The main element has tabindex="-1" so the skip link moves focus there. OsirionFooter inside the layout's footer slot renders a div, so the page keeps one footer landmark. |
OsirionPageLayout, OsirionFooter |
| Named navigation | nav elements carry an aria-label: Menu ("Navigation menu", set with AriaLabel), breadcrumbs ("breadcrumb"), the table of contents ("Table of Contents"), and the document navigation and pagination of DocumentPage. The search box is a form with role="search". |
Menu, SearchBox |
| Focus styles | Interactive elements get an outline on keyboard focus (:focus-visible), drawn from --osirion-focus-ring-color, --osirion-focus-ring-width and --osirion-focus-ring-offset. The default color is an opaque step of the theme's primary scale (--osirion-color-primary-600, in the framework's primary color under an adapter), and every palette sets its own, so the ring reaches 3:1 on the page and on card and panel surfaces (WCAG 2.2, 1.4.11 Non-text Contrast). |
Theming, Menu, ThemeToggle |
| Reduced motion | Under prefers-reduced-motion: reduce the header does not hide on scroll, the carousels and the metric count-up do not animate, and ThemeToggle switches themes without its fade. |
Core, Theming |
| Labelled controls | Contact form fields have a label bound with for and an aria-describedby that points at the validation message. The theme toggle and the menu toggle have an aria-label. The honeypot field of the contact form is aria-hidden and has tabindex="-1". |
OsirionContactForm, ThemeToggle |
| Scrollable content | Code blocks and tables in rendered Markdown get tabindex="0", so a keyboard user can scroll them. FocusableScrollBlocks="false" turns this off. |
OsirionHtmlRenderer |
| Cookie consent | The banner is a region named by its Title. |
OsirionCookieConsent |
Some motion fixes arrive in the release after 4.1.0: the changelog lists OsirionPageLoading, OsirionBackgroundPattern
and OsirionReveal under Unreleased for their behavior under reduced motion. Read
the changelog for the version you run.
Know what the repository tests
The contrast of the theme colors is held by tests in tests/Osirion.Blazor.Theming.Tests:
OsirionThemeContrastTestsreads the light and dark theme files and checks every text pair (primary, secondary and tertiary text on each background, links, button text, the active navigation item, status messages and form inputs) for a contrast ratio of at least 4.5:1, and the focus border for at least 3:1.PaletteStylesheetTestsholds each variant of each palette to the text contrast target of that variant, and the code colors to the code background.AdapterContrastTestsholds the active navigation item to 4.5:1 under the Bootstrap, Fluent UI, MudBlazor and Radzen adapters, in both themes. This test arrives in the release after 4.1.0, together with the color changes it checks.
tests/Osirion.Blazor.Core.Tests checks the skip link and the landmarks of OsirionPageLayout. The continuous
integration workflow runs dotnet test on every pull request and every push to master, so these tests run there. The workflows do not run an automated
checker such as axe, so read these results as checks of the library's own markup and colors, not of your pages.
Run the contrast tests yourself from a clone of the repository:
dotnet test tests/Osirion.Blazor.Theming.Tests -c Release
Do a keyboard pass and a screen reader pass
These two passes find what no stylesheet check can. Run them on your own pages, not on the examples.
- Reload the page and press
Tabonce. The skip link appears at the top left. PressEnter: focus moves to the main content, and the nextTabgoes to the first link or control inside it. - Keep pressing
Tabthrough the page. Every control you can click must receive focus, in reading order, with a visible outline. Nothing may trap focus. - Open the menu, the theme toggle and any tabs or accordion with the keyboard alone (
EnterorSpace, arrow keys for tabs). - Turn on a screen reader and open its landmarks or headings list. You should find the header, the navigation, one
main region and the footer, and a heading outline with one
h1that does not skip levels. - Move to each control and listen to its name. A control announced as "button" or "link" alone has no name.
Run an automated checker
An automated checker finds a part of the problems: missing names, duplicate ids, the contrast of text it can compute. Use the axe browser extension, or the command line:
npx @axe-core/cli http://localhost:5000
Replace the address with the one your site listens on. Fix what it reports on your own pages. A clean report does not mean the page works with a keyboard or a screen reader, so keep the keyboard and screen reader passes for what a tool cannot judge.
Do the part the library cannot do
The library renders what you give it. These stay your job:
- Alt text.
OsirionResponsiveImagetakesAlt, which defaults to an empty string: the image is then decorative. Write a description for every image that carries information. - Heading order. Write one
h1per page and do not skip levels in your Markdown.ArticlePage(with its hero),DocumentPage,HomePage(with its hero),AboutPageandContactPagerender the page title as theh1and leave an opening# Titleout of the body, so start your sections at##. - Link text. Write links that make sense out of context. "Read the migration guide" works, "click here" does not.
- Your own colors. The tests hold the theme and palette colors only. If you set custom properties or write your
own CSS, check the contrast of what you changed, including the focus outline, which needs 3:1 on every surface it is drawn on, so avoid a translucent color. The themes and palettes set the focus
ring variables on the
htmlelement, so load your stylesheet after Osirion's and match their selectors:
:root[data-osirion-theme],
:root[data-osirion-palette][data-osirion-theme] {
--osirion-focus-ring-color: #1d4ed8;
--osirion-focus-ring-width: 3px;
}
- Language. Set
langon thehtmlelement in yourApp.razor, and setSkipLinkTextin the language of the page. - Content that moves or flashes. Avoid it, and give a way to stop it.
The skip link text, the main region id and an image description are set like this:
<OsirionPageLayout SkipLinkText="Zum Inhalt springen" MainContentId="content">
<Body>
<OsirionResponsiveImage Src="/images/team.jpg" Alt="The team at the 2026 meetup" Width="800" Height="600" />
</Body>
</OsirionPageLayout>
Check that it works
- The skip link appears on the first
Taband moves focus intomain. - Every interactive element shows a focus outline and has a name that a screen reader announces.
- The axe run reports nothing on your pages, or only items you have reviewed.
dotnet test tests/Osirion.Blazor.Theming.Tests -c Releasepasses in a clone of the repository.
If the skip link does not appear, your pages may not use OsirionPageLayout (which OsirionSiteLayout builds on), or
ShowSkipLink is false. If it appears but does nothing, check that MainContentId is unique on the page.
Next steps
OsirionPageLayout: the skip link, the landmarks and the hide-on-scroll header.- Palettes: the color sets the contrast tests cover, including the
Contrastpalette. ThemeToggleandThemePicker: theme controls with names.- Security: the other half of running a site in production.