open regard. Module 01 / Display / Runnable examples

01 / Vanilla HTML

One preference.
Across the website.

Change the display profile and try the form, cards and second control below. Open the static docs in another tab to see the same selection there.

A small reading workspace

Flexible layout · Paired surfaces · Native form

Reading notes / 001

Give the content room.

A display preference should work beyond a paragraph. This sample includes navigation, form controls and different surfaces, with space to grow when text or spacing increases.

Palette check

Foreground + background

Keep color pairs together.

Vision + High Contrast uses a restrained green palette and stronger borders. Max Contrast switches to black and white. Both define each surface and its text together.

Same controller / A different style

Two controls, one preference.

This second widget hides the decorative icon. Its native select stays in sync without moving focus.

The Vision profiles compose wcagPresets.textSpacing with htmlPresets.nativeControls. The first supplies presentation tokens; native HTML supplies labels and control behavior. Inspect config.js and demo.css below.

Source code

These are the files behind this example. The tabs support arrow keys, Home and End.

index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>Vanilla HTML — Open Regard Display</title>
    <!-- Self-host synchronous scripts so the saved profile applies before paint. -->
    <script src="../dist/display.browser.js"></script>
    <script src="../dist/presets.browser.js"></script>
    <script src="./config.js"></script>
    <link rel="stylesheet" href="../dist/style.css" />
    <link rel="stylesheet" href="./demo.css" />
    <link rel="icon" href="./mark.svg" type="image/svg+xml" />
  </head>
  <body>
    <a class="skip" href="#main">Skip to content</a>
    <header class="masthead shell">
      <a class="brand" href="https://openregard.org/"
        ><img src="./mark.svg" alt="" />open regard.</a
      >
      <span class="meta">Module 01 / Display / Runnable examples</span>
    </header>
    <nav class="example-nav shell" aria-label="Example navigation">
      <a href="./" aria-current="page">Vanilla HTML</a
      ><a href="./docs.html">Static docs</a><a href="./react.html">React</a
      ><a href="https://openregard.org/docs/">Library documentation ↗</a>
    </nav>
    <main id="main" class="shell">
      <section class="hero">
        <div>
          <p class="eyebrow">01 / Vanilla HTML</p>
          <h1>One preference.<br /><em>Across the website.</em></h1>
          <p class="intro">
            Change the display profile and try the form, cards and second
            control below. Open the static docs in another tab to see the same
            selection there.
          </p>
        </div>
        <aside class="control-card" aria-label="Display settings">
          <p class="eyebrow">Try a display profile</p>
          <div id="controls"></div>
        </aside>
      </section>

      <div class="section-head">
        <h2>A small reading workspace</h2>
        <p>Flexible layout · Paired surfaces · Native form</p>
      </div>
      <div class="grid">
        <article class="card">
          <p class="eyebrow">Reading notes / 001</p>
          <h2>Give the content room.</h2>
          <p>
            A display preference should work beyond a paragraph. This sample
            includes navigation, form controls and different surfaces, with
            space to grow when text or spacing increases.
          </p>
          <label
            >Search the example<input
              type="search"
              placeholder="A native search field to try"
          /></label>
        </article>
        <article class="card dark">
          <p class="eyebrow">Palette check</p>
          <span class="tag">Foreground + background</span>
          <h2 style="margin-top: 1.5rem">Keep color pairs together.</h2>
          <p>
            Vision + High Contrast uses a restrained green palette and stronger
            borders. Max Contrast switches to black and white. Both define each
            surface and its text together.
          </p>
          <button type="button" id="reset">Reset preferences</button>
        </article>
      </div>
      <section class="sync-row">
        <div>
          <p class="eyebrow">Same controller / A different style</p>
          <h2>Two controls, one preference.</h2>
          <p>
            This second widget hides the decorative icon. Its native select
            stays in sync without moving focus.
          </p>
        </div>
        <div id="secondary"></div>
      </section>
      <p class="recipe-note">
        The Vision profiles compose <code>wcagPresets.textSpacing</code> with
        <code>htmlPresets.nativeControls</code>. The first supplies presentation
        tokens; native HTML supplies labels and control behavior. Inspect
        <strong>config.js</strong> and <strong>demo.css</strong> below.
      </p>

      
    </main>
    <footer class="shell">
      <p>
        Open Regard / Display. Profiles and page styles are configured by the
        site. Test your integration with your content and users.
      </p>
      <a href="https://github.com/inferal-oss/openregard">View the project ↗</a>
    </footer>
    <script>
      OpenRegardDisplay.mountDisplayWidget(
        document.getElementById("controls"),
        regard,
        {
          className: "demo-widget",
        },
      );
      OpenRegardDisplay.mountDisplayWidget(
        document.getElementById("secondary"),
        regard,
        {
          icon: false,
          className: "demo-widget",
        },
      );
      document.getElementById("reset").onclick = () => regard.reset();
    </script>
  </body>
</html>
config.js
// Optional token recipes. Profile names, composition and site styling are yours.
const { wcagPresets, htmlPresets } = OpenRegardPresets;
window.regardConfig = {
  version: 1,
  defaultProfile: "standard",
  storageKey: "openregard-example",
  controlLabel: "Reading and display preferences",
  profiles: [
    {
      id: "standard",
      label: "Standard",
      description: "The original site presentation.",
    },
    {
      id: "roomy",
      label: "Vision",
      description: "Larger text with the WCAG text-spacing override values.",
      tokens: {
        ...wcagPresets.textSpacing,
        ...htmlPresets.nativeControls,
        "--regard-font-size": "125%",
      },
    },
    {
      id: "vision-contrast",
      label: "Vision + High Contrast",
      description:
        "Larger, spaced text with a restrained palette and stronger borders.",
      tokens: {
        ...wcagPresets.textSpacing,
        ...wcagPresets.contrastLight,
        ...htmlPresets.nativeControls,
        "--regard-font-size": "125%",
      },
    },
    {
      id: "strong",
      label: "Max Contrast",
      description:
        "Larger text, generous spacing and black-and-white surfaces.",
      tokens: {
        ...wcagPresets.textSpacing,
        ...htmlPresets.nativeControls,
        "--regard-font-size": "150%",
        "--regard-page-ink": "#000",
        "--regard-page-paper": "#fff",
        "--regard-panel-ink": "#fff",
        "--regard-panel-paper": "#000",
        "--regard-border-color": "#000",
      },
    },
  ],
};
window.regard = OpenRegardDisplay.createDisplay(window.regardConfig);
window.stopRegard = window.regard.start();
demo.css
:root {
  font-size: var(--regard-font-size, 100%);
  --ink: var(--regard-page-ink, #203b32);
  --paper: var(--regard-page-paper, #f4f5ee);
  --muted: var(--regard-page-ink, #52645b);
  --line: var(--regard-border-color, #c5cec0);
  --panel-paper: var(--regard-panel-paper, #203b32);
  --panel-ink: var(--regard-panel-ink, #f4f7ee);
  --surface: var(--regard-page-paper, #fffef8);
  --accent: var(--regard-page-paper, #d8ebbb);
  color: var(--ink);
  background: var(--paper);
  font-family:
    ui-sans-serif,
    system-ui,
    -apple-system,
    sans-serif;
  line-height: var(--regard-line-height, 1.65);
  letter-spacing: var(--regard-letter-spacing, normal);
  word-spacing: var(--regard-word-spacing, normal);
}
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  overflow-wrap: anywhere;
}
.shell {
  width: min(100% - 3rem, 76rem);
  margin-inline: auto;
}
a {
  color: inherit;
  text-underline-offset: 0.25em;
}
:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: 4px;
}
.skip {
  position: absolute;
  transform: translateY(-150%);
  background: Canvas;
  color: CanvasText;
  padding: 0.7em;
  z-index: 5;
}
.skip:focus {
  transform: none;
}
.masthead {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  align-items: center;
  padding-block: 1.5rem;
}
.brand {
  display: inline-flex;
  gap: 0.65em;
  align-items: center;
  font-weight: 700;
  font-size: 1.3rem;
  letter-spacing: -0.04em;
  text-decoration: none;
}
.brand img {
  width: 2rem;
  height: 2rem;
}
.masthead .meta {
  font-size: 0.75rem;
  color: var(--muted);
}
.example-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.5rem;
  padding-block: 0.8rem;
  border-block: 1px solid var(--line);
  font-size: 0.85rem;
}
.example-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75em;
  text-decoration: none;
}
.example-nav [aria-current] {
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.55em;
}
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 5rem);
  padding-block: 3.5rem;
  align-items: start;
}
.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.7rem;
  font-weight: 700;
}
h1 {
  font-size: clamp(2.4rem, 5vw, 4.4rem);
  line-height: 1.1;
  letter-spacing: -0.055em;
  margin: 0.8rem 0 1.5rem;
  font-weight: 600;
}
h1 em {
  font-family: Georgia, serif;
  font-weight: 400;
}
h2 {
  font-size: clamp(1.5rem, 3vw, 2.2rem);
  line-height: 1.2;
  letter-spacing: -0.035em;
  font-weight: 600;
  margin-top: 0;
}
h3 {
  line-height: 1.3;
  font-size: 1.1rem;
}
p {
  margin-block: 0 1em;
  margin-block-end: var(--regard-paragraph-spacing, 1em);
}
.intro {
  font-size: 1.05rem;
  color: var(--muted);
  max-width: 39rem;
}
.control-card {
  padding: 1.5rem;
  border: 1px solid var(--line);
  border-radius: 0.8rem;
  background: var(--surface);
  box-shadow: 0 8px 0 var(--accent);
  min-width: 0;
}
.control-card .eyebrow {
  margin-bottom: 1rem;
}
/* The same public styling hooks work on React and vanilla widgets. */
.demo-widget {
  --openregard-control-radius: 0.4rem;
  --openregard-control-padding: 0.75em;
  --openregard-gap: 0.6rem;
  --openregard-focus-color: var(--ink);
}
.demo-widget .openregard-label {
  flex: 1;
  font-size: 0.8rem;
  font-weight: 600;
}
.demo-widget .openregard-select {
  width: 100%;
}
.demo-widget .openregard-description {
  font-size: 0.78rem;
  margin-top: 0.8rem;
  color: var(--muted);
}
.section-head {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  margin-block: 1rem 1.5rem;
}
.section-head h2 {
  margin: 0;
}
.section-head p {
  font-size: 0.8rem;
  color: var(--muted);
  margin: 0;
}
.grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
}
.card {
  border: 1px solid var(--line);
  border-radius: 0.7rem;
  padding: clamp(1.1rem, 3vw, 2rem);
  background: var(--surface);
  min-width: 0;
}
.card .eyebrow {
  margin-bottom: 1.4rem;
}
.dark {
  background: var(--panel-paper);
  color: var(--panel-ink);
  border-color: currentColor;
}
.dark p {
  color: inherit;
}
.large-number {
  font-family: Georgia, serif;
  font-size: 3.5rem;
  line-height: 1.2;
}
.tag {
  display: inline-block;
  border: 1px solid currentColor;
  border-radius: 2rem;
  padding: 0.2em 0.7em;
  font-size: 0.7rem;
}
label:not(.openregard) {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
}
input,
button {
  box-sizing: border-box;
  font: inherit;
  max-width: 100%;
  min-width: 0;
}
input {
  display: block;
  width: 100%;
  margin-top: 0.5em;
  padding: 0.75em;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 0.35rem;
}
button {
  cursor: pointer;
  padding: 0.65em 0.9em;
  background: Canvas;
  color: CanvasText;
  border: 1px solid currentColor;
  border-radius: 0.35rem;
}
.sync-row {
  margin-block: 1.5rem 3rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 2rem;
  align-items: center;
  padding: 2rem;
  background: var(--accent);
  border: 1px solid var(--line);
  border-radius: 0.7rem;
}
.sync-row p {
  font-size: 0.85rem;
}
.doc-layout {
  display: grid;
  grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: 3rem;
}
.doc-index {
  border-top: 1px solid var(--line);
  padding-top: 1rem;
  font-size: 0.8rem;
}
.doc-index a {
  display: block;
  padding-block: 0.6em;
}
.doc-article {
  min-width: 0;
  max-width: 48rem;
}
.doc-article section {
  padding-block: 1rem 2rem;
}
.steps {
  padding-inline-start: 1.5rem;
}
.steps li {
  padding-inline-start: 0.4em;
  margin-block: 1em;
}
code {
  font-size: 0.88em;
  overflow-wrap: anywhere;
}
.code-note {
  padding: 1.5rem;
  background: var(--panel-paper);
  color: var(--panel-ink);
  border-radius: 0.5rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.7;
}
.recipe-note {
  border-left: 3px solid currentColor;
  padding-inline-start: 1rem;
  font-size: 0.85rem;
}
footer {
  border-top: 1px solid var(--line);
  padding-block: 2rem;
  margin-top: 3rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  font-size: 0.8rem;
  color: var(--muted);
}
footer p {
  margin: 0;
  max-width: 40rem;
}
/* Spacing overrides also reach typography with authored heading/tracking values. */
:root:not([data-regard-profile="standard"])
  :is(h1, h2, h3, p, a, label, span, select, button, li) {
  line-height: var(--regard-line-height, 1.65);
  letter-spacing: var(--regard-letter-spacing, normal);
  word-spacing: var(--regard-word-spacing, normal);
}
@media (max-width: 850px) {
  .hero,
  .doc-layout {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
  .hero {
    padding-block: 2rem 3rem;
  }
  .doc-index {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
  }
}
@media (max-width: 600px) {
  .shell {
    width: calc(100% - 2rem);
  }
  .grid,
  .sync-row {
    grid-template-columns: 1fr;
  }
  .sync-row {
    padding: 1.25rem;
    gap: 1rem;
  }
  .masthead {
    padding-block: 1rem;
  }
}
@media (forced-colors: active) {
  .dark,
  .code-note {
    background: Canvas;
    color: CanvasText;
  }
  .control-card {
    box-shadow: none;
  }
}