Build a B.C.-style reminder preference form with real semantic tokens, native React Aria controls, conditional contact fields and complete validation behavior.
B.C. Design System Current React Library and Tokens
Choose the maintained implementation
The current B.C. Design System provides React components built on React Aria. This example pins react-components 0.8.1 and its design-tokens 5.0.0 dependency. The older B.C. Web Components repository is a separate legacy implementation; importing it does not reproduce the current React library. Match the implementation to the documentation before copying an example.
Import the actual font face
The components expect the BC Sans family name with a space. Version 2.1.2 provides css/BC_Sans.css; the old BCSans.css entry is marked deprecated and declares a different family name. A developer machine with BC Sans installed can conceal a missing font import. The specimen bundles the published font so the result does not depend on a local installation.
B.C. Design System Semantic Color and Spacing Roles
Read the role before choosing the value
Primary buttons use the dark-blue primary-button fill, while supporting content uses typography-color-secondary. Error messages use typography-color-danger. The table records the current CSS export names; the name conveys a stable intent even when a future theme changes the underlying value. Avoid confusing an inactive control color with ordinary supporting text.
Keep geometry deliberate
The form uses 24px field spacing and a wider 48px gap between the main task and supporting explanation. Those values correspond to the library rhythm, while the overall two-column composition is authored for this specimen. The mobile layout collapses the columns without shrinking the form labels or turning explanatory text into a tooltip.
B.C. Design System Conditional Fields and Retained Values
Validate only the chosen contact method
A native RadioGroup controls whether the Email address or Phone number TextField is visible. Both values stay in React state when the method changes, but only the selected field participates in review validation. This keeps useful input while preventing an invisible field from blocking the current task.
Show useful local errors
The email field checks a simple address shape, and the phone example requires at least ten digits. These are explicitly sample rules, not a complete international contact validator. Invalid review sets isInvalid and provides a field-specific errorMessage. Missing agreement gets a visible message; the first invalid control receives focus.
B.C. Design System React Aria Component Contracts
Use controlled values and documented handlers
TextField receives value and onChange; RadioGroup receives value and onChange; Checkbox uses isSelected and onChange. These handlers receive their documented values, not a browser event object that must always be read through event.target. Button uses type=submit and the native form’s submit event so keyboard submission shares the same validation path.
Keep review feedback synchronized
B.C. Design System Accessible Names and Responsive Composition
Keep labels, descriptions and errors connected
The native components provide their React Aria relationships for labels, help text and error messages. The application still supplies meaningful labels, a clear group description and understandable validation text. Testing must click visible radio labels and use the keyboard; the internal visually hidden input is not the visible target.
Separate supporting guidance from the form
The adjacent callout explains the local workflow and includes a native details disclosure with implementation context. At narrow widths it follows the form in the reading order. The information symbol is decorative because the heading carries the meaning. No official B.C. logo or government-service claim is required to study the components.
B.C. Design System Complete React Implementation
Reproduce the verified source
Create a Vite React project and install the pinned component, token and font packages. Use the supplied main.jsx and bc.css with a root mount element. The bundle includes native radio, field, checkbox and button behavior plus the complete local validation and state transitions. No private API or credential is necessary.
Install the pinned packages and import css/BC_Sans.css.
Save main.jsx and bc.css, keeping the root mount element.
Submit an empty form, then correct the visible field.
Switch methods and confirm the previous value is retained.
Keep conditional validation aligned with the selected method
RadioGroup and TextField onChange handlers receive values, while Checkbox onChange receives the selected boolean. Store those values directly rather than applying a generic event.target.value handler to every component. The visible labels remain the interaction targets even when React Aria visually hides a native input.
When the contact method changes, retain both draft values but clear the old review and validate only the chosen method. Move focus to the first invalid visible control after submission. This lets a person compare contact options without losing an email address or being blocked by an invisible phone field. The sample’s ten-digit phone rule is deliberately local and must be replaced with the service’s actual international-number requirements.
Only the selected contact field is validated.
Editing any choice clears old review feedback.
The result does not claim a reminder was scheduled.
B.C. Design System Design System Component Examples
main.jsx — complete working specimen
Choose and review a contact preference. The source below is the full React entry, including all state and validation.
jsx
import React, { useState, useRef } from "react";
import { createRoot } from "react-dom/client";
import {
Button,
Radio,
RadioGroup,
TextField,
Checkbox,
} from "@bcgov/design-system-react-components";
import "@bcgov/bc-sans/css/BC_Sans.css";
import "./bc.css";
function App() {
const [method, setMethod] = useState("email"),
[email, setEmail] = useState(""),
[phone, setPhone] = useState(""),
[consent, setConsent] = useState(false),
[submitted, setSubmitted] = useState(false),
[result, setResult] = useState("");
const panel = useRef(null);
const invalidEmail = !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email),
invalidPhone = phone.replace(/\D/g, "").length < 10;
function change(fn, value) {
fn(value);
setResult("");
setSubmitted(false);
}
function review(e) {
e.preventDefault();
setSubmitted(true);
if ((method === "email" ? invalidEmail : invalidPhone) || !consent) {
requestAnimationFrame(() =>
panel.current
.querySelector(
'[aria-invalid="true"] input,input[aria-invalid="true"],input[type=checkbox]:not(:checked)',
)
?.focus(),
);
return;
}
setResult(
`Local preference ready: ${method === "email" ? "Email to " + email : "Phone call to " + phone}. No reminder has been scheduled.`,
);
}
return (
<main>
<header>
<div className="eyebrow">
SERVICE REMINDER / ORIGINAL APPLICATION STUDY
</div>
<h1>Choose how to hear from us</h1>
<p>
Set a sample reminder preference. Use fictional contact details in
this local example.
</p>
</header>
<div className="columns">
<form onSubmit={review} noValidate ref={panel}>
<RadioGroup
label="Contact method"
value={method}
onChange={(v) => change(setMethod, v)}
description="Choose one way to receive a reminder."
>
<Radio value="email">Email</Radio>
<Radio value="phone">Phone call</Radio>
</RadioGroup>
<div className="field">
{method === "email" ? (
<TextField
label="Email address"
type="email"
value={email}
onChange={(v) => change(setEmail, v)}
isRequired
isInvalid={submitted && invalidEmail}
errorMessage="Enter an email address in the format [email protected]."
description="Use a sample address, such as [email protected]."
/>
) : (
<TextField
label="Phone number"
type="tel"
value={phone}
onChange={(v) => change(setPhone, v)}
isRequired
isInvalid={submitted && invalidPhone}
errorMessage="Enter a phone number with at least 10 digits."
description="Sample validation only; a real service needs a jurisdiction-aware phone rule."
/>
)}
</div>
<div className="field">
<Checkbox
isSelected={consent}
onChange={(v) => change(setConsent, v)}
isInvalid={submitted && !consent}
>
I agree to use these details for this sample reminder
</Checkbox>
{submitted && !consent && (
<p className="error" role="alert">
Confirm the reminder preference before continuing.
</p>
)}
</div>
<Button type="submit" variant="primary">
Review preference
</Button>
<p className="result" role="status">
{result}
</p>
</form>
<aside>
<div className="status-mark" aria-hidden="true">
i
</div>
<h2>What happens next</h2>
<ol>
<li>Choose a contact method.</li>
<li>Review the sample details.</li>
<li>Connect a real notification service before scheduling.</li>
</ol>
<p>
This example keeps both fields while switching methods, but only
reviews the selected method.
</p>
<details>
<summary>About this specimen</summary>
<p>
Native B.C. React Aria components with BC Sans. The form is
original and is not an official government service.
</p>
</details>
</aside>
</div>
</main>
);
}
createRoot(document.getElementById("root")).render(<App />);
Save beside main.jsx. These custom composition rules are distinguished from the library token reference.
04
B.C. Design System Agent Setup
Implementation Starting Point
The pinned native example was bundled and browser-checked locally. The specimen uses only local application state.
sh
npm create vite@latest bc-reminder -- --template react
cd bc-reminder
npm install
npm install @bcgov/[email protected] @bcgov/[email protected] @bcgov/[email protected]
# Replace src/main.jsx and add src/bc.css using the complete examples.
npm run dev
A Prompt for Your Project
Agent Prompt
Build the reminder form with B.C. React components 0.8.1 and BC Sans 2.1.2. Preserve conditional validation, retained input, visible errors and stale-result clearing. Use the current token names and correct spaced font family. Keep the example local until a real notification contract exists.
05
B.C. Design System Sources and Scope
An OpenDesign application study using the current public B.C. React library. This is an original local form, not an official government service; use fictional contact details.