현재 B.C. Design System는 React Aria를 기반으로 구축된 React 컴포넌트를 제공합니다. 이 예제에서는 react-components 0.8.1과 해당 design-tokens 5.0.0 종속 항목을 고정해 사용합니다. 이전 B.C. Web Components 저장소는 별도의 레거시 구현입니다. 이를 가져와도 현재 React 라이브러리와 동일하게 동작하지 않습니다. 예제를 복사하기 전에 문서와 구현이 일치하는지 확인하세요.
실제 글꼴을 가져오세요
컴포넌트는 공백이 포함된 BC Sans 글꼴 패밀리 이름을 사용합니다. 버전 2.1.2에는 css/BC_Sans.css가 제공됩니다. 이전 BCSans.css 항목은 더 이상 사용되지 않는 것으로 표시되어 있으며 다른 패밀리 이름을 선언합니다. 개발자 컴퓨터에 BC Sans가 설치되어 있으면 글꼴 가져오기가 누락된 사실을 알아차리지 못할 수 있습니다. 이 예제에는 공개된 글꼴을 포함해 로컬 설치 여부에 상관없이 같은 결과가 나오도록 했습니다.
B.C. 디자인 시스템 시맨틱 색상 및 간격 역할
값을 선택하기 전에 역할을 확인하세요
기본 버튼에는 진한 파란색 기본 버튼 채우기 색상을 사용하고, 보조 콘텐츠에는 typography-color-secondary를 사용합니다. 오류 메시지에는 typography-color-danger를 사용합니다. 표에는 현재 CSS에서 내보내는 이름이 기록되어 있습니다. 향후 테마에서 실제 값이 달라져도 이름은 일관된 용도를 나타냅니다. 비활성 컨트롤 색상을 일반 보조 텍스트 색상과 혼동하지 마세요.
간격을 신중하게 설정하세요
양식에는 필드 사이에 24px 간격을 두고, 주 작업 영역과 보조 설명 사이에는 더 넓은 48px 간격을 둡니다. 이 값은 라이브러리의 간격 체계에 해당하지만, 전체 2열 구성은 이 예제를 위해 별도로 만들었습니다. 모바일 레이아웃에서는 열을 하나로 합치되 양식 레이블을 축소하거나 설명 텍스트를 툴팁으로 바꾸지 않습니다.
B.C. 디자인 시스템 조건부 필드와 값 유지
선택한 연락 방법만 유효성을 검사하세요
네이티브 RadioGroup으로 이메일 주소 또는 전화번호 TextField의 표시 여부를 제어합니다. 연락 방법을 바꿔도 두 입력값은 React 상태에 그대로 유지되지만, 검토 시에는 선택한 필드만 유효성 검사에 포함됩니다. 이렇게 하면 입력값은 유지하면서 현재 작업에 표시되지 않는 필드가 작업을 막지 않도록 할 수 있습니다.
유용한 오류 메시지를 표시하세요
이메일 필드는 기본적인 주소 형식을 검사하고, 전화번호 예제는 숫자가 10개 이상인지 확인합니다. 이는 완전한 국제 연락처 유효성 검사 규칙이 아닌 샘플 규칙입니다. 검토 결과가 유효하지 않으면 isInvalid를 설정하고 해당 필드에 맞는 errorMessage를 표시합니다. 동의 항목을 선택하지 않은 경우에도 메시지를 표시하며, 유효하지 않은 첫 번째 컨트롤로 포커스를 이동합니다.
B.C. 디자인 시스템 React Aria 컴포넌트 계약
제어되는 값과 문서화된 핸들러를 사용하세요
TextField에는 value와 onChange를, RadioGroup에는 value와 onChange를 전달합니다. Checkbox에는 isSelected와 onChange를 사용합니다. 이 핸들러는 문서화된 값을 전달받으며, 항상 event.target을 통해 읽어야 하는 브라우저 이벤트 객체를 전달받는 것이 아닙니다. Button에는 type=submit을 사용하고 네이티브 양식의 submit 이벤트를 이용해 키보드로 양식을 제출해도 같은 유효성 검사 경로를 따르도록 합니다.
검토 결과를 최신 상태로 유지하세요
B.C. 디자인 시스템 접근 가능한 이름 및 반응형 구성
레이블, 설명, 오류 메시지를 서로 연결하세요
네이티브 컴포넌트는 레이블, 도움말 텍스트, 오류 메시지에 대해 React Aria의 연결 관계를 제공합니다. 애플리케이션에서도 의미 있는 레이블, 명확한 그룹 설명, 이해하기 쉬운 유효성 검사 문구를 제공해야 합니다. 테스트할 때는 화면에 표시된 라디오 레이블을 클릭하고 키보드로 조작해야 합니다. 내부의 시각적으로 숨겨진 입력 요소는 화면에서 직접 조작하는 대상이 아닙니다.
보조 안내와 양식을 분리하세요
옆에 배치된 안내 상자는 로컬 작업 흐름을 설명하고, 구현 관련 정보를 담은 네이티브 details 펼침 영역을 포함합니다. 화면 너비가 좁아지면 읽는 순서에 따라 양식 뒤에 표시됩니다. 정보 기호는 장식용이며 제목이 의미를 전달합니다. 컴포넌트를 살펴보는 데 B.C. 공식 로고나 정부 서비스라는 주장은 필요하지 않습니다.
B.C. 디자인 시스템 전체 React 구현
검증된 소스를 그대로 재현하세요
Vite React 프로젝트를 만들고 버전을 고정한 컴포넌트, 토큰, 글꼴 패키지를 설치하세요. 제공된 main.jsx와 bc.css를 루트 마운트 요소와 함께 사용합니다. 번들에는 네이티브 라디오, 필드, 체크박스, 버튼 동작과 완전한 로컬 유효성 검사 및 상태 전환이 포함되어 있습니다. 비공개 API나 자격 증명은 필요하지 않습니다.
버전을 고정한 패키지를 설치하고 css/BC_Sans.css를 가져오세요.
main.jsx와 bc.css를 저장하고 루트 마운트 요소를 그대로 유지하세요.
양식을 비워 둔 채 제출한 다음, 표시된 필드의 값을 올바르게 수정하세요.
연락 방법을 전환하고 이전 입력값이 유지되는지 확인하세요.
선택한 연락 방법에 따라 조건부 유효성 검사가 적용되도록 하세요
RadioGroup과 TextField의 onChange 핸들러는 값을 전달받고, Checkbox의 onChange 핸들러는 선택 여부를 불리언으로 전달받습니다. 모든 컴포넌트에 일반적인 event.target.value 핸들러를 적용하지 말고 전달받은 값을 그대로 저장하세요. React Aria가 네이티브 입력 요소를 시각적으로 숨기더라도 화면에 보이는 레이블은 계속 조작 대상으로 유지됩니다.
연락 방법이 바뀌어도 두 입력값은 모두 유지하되, 이전 검토 결과를 지우고 선택한 방법만 검증합니다. 제출 후에는 오류가 있는 첫 번째 표시 컨트롤로 포커스를 이동합니다. 이렇게 하면 이메일 주소를 잃거나 화면에 보이지 않는 전화번호 입력란 때문에 진행이 막히지 않아, 연락 방법을 비교해 볼 수 있습니다. 예시의 10자리 전화번호 규칙은 의도적으로 지역에 한정되어 있으므로 실제 서비스의 국제 전화번호 요건에 맞게 바꿔야 합니다.
선택한 연락처 입력란만 검증합니다.
선택 항목을 수정하면 이전 검토 피드백이 지워집니다.
결과에는 알림이 예약되었다고 표시되지 않습니다.
B.C. 디자인 시스템 구성 요소 예시
main.jsx — 완전히 작동하는 예제
연락 방법을 선택하고 검토합니다. 아래 소스는 모든 상태와 검증 로직을 포함한 전체 React 항목입니다.
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 />);
main.jsx와 같은 위치에 저장하세요. 이 사용자 지정 레이아웃 규칙은 라이브러리 토큰 참조와 구분됩니다.
04
B.C. 디자인 시스템 에이전트 설정
구현 시작점
고정된 기본 예제를 번들링한 뒤 로컬 브라우저에서 확인했습니다. 이 예제는 로컬 애플리케이션 상태만 사용합니다.
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
프로젝트를 위한 프롬프트
에이전트 프롬프트
B.C. React 구성 요소 0.8.1과 BC Sans 2.1.2를 사용해 알림 양식을 만드세요. 조건부 검증, 입력값 유지, 오류 표시, 오래된 결과 지우기 동작을 보존하세요. 최신 토큰 이름과 공백이 올바르게 포함된 글꼴 패밀리 이름을 사용하세요. 실제 알림 계약이 마련될 때까지 예제를 로컬에서만 사용하세요.
05
B.C. 디자인 시스템 출처 및 범위
현재 공개된 B.C. React 라이브러리를 활용한 OpenDesign 애플리케이션 연구입니다. 이 양식은 공식 정부 서비스가 아니라 독립적으로 제작한 로컬 양식이므로, 가상의 연락처 정보를 사용하세요.