Accessibility and APCA Contrast
Declare contrast requirements in tokens and check them across every resolved mode.
Facet stores contrast requirements in token data and evaluates them after aliases, derivations, and
mode sets have resolved. The supported metrics in the source spec are WCAG21 and APCA.
Declaring contrast pairs
The theme files declare readable foreground/background pairs:
{
"ink": {
"$value": "{color.text.strong}",
"$extensions": { "com.facet": { "a11y": [
{ "pairsWith": "{color.bg}", "minContrast": 4.5, "metric": "WCAG21" },
{ "pairsWith": "{color.surface}", "minContrast": 4.5, "metric": "WCAG21" }
] } }
},
"ink-muted": {
"$value": "{color.text.muted}",
"$extensions": { "com.facet": { "a11y": [
{ "pairsWith": "{color.surface}", "minContrast": 4.5, "metric": "WCAG21" }
] } }
}
}
Brand files declare button foreground contrast:
{
"on-action": {
"$value": "{color.white}",
"$extensions": { "com.facet": { "a11y": [
{ "pairsWith": "{color.action}", "minContrast": 4.5, "metric": "WCAG21" }
] } }
}
}
Checking every mode
Run:
facet check tokens/app.resolver.json
The checker evaluates declared contrast pairs on resolved token values in every permutation. In the checked-in graph, that means light and dark themes, three brands, and comfortable or compact density. Density does not change colors, but it is still part of the resolver's permutation space.
APCA status
The spec allows:
{ "pairsWith": "{color.surface}", "minContrast": 60, "metric": "APCA" }
The source docs state that check.mjs computes WCAG2 and APCA contrast, but the checked-in example
token files use WCAG21 thresholds. Use APCA only where your token policy defines the threshold
values you want to enforce.
Brand foreground selection
The globex source file documents an important guardrail: its orange action color uses dark text
for on-action because white fails contrast on orange.
{
"on-action": {
"$value": "{color.text.strong}",
"$extensions": { "com.facet": { "a11y": [
{ "pairsWith": "{color.action}", "minContrast": 4.5, "metric": "WCAG21" }
] } }
}
}
This keeps component code unchanged:
<button class="bg-action fg-on-action radius-control px-inset-lg py-inset-md">
Primary action
</button>
The brand set, not the component, decides which foreground token satisfies contrast.