Skip to content
Kinetixui

How to verify design system parity across web, iOS and Android

Guide · part of Cross-platform design systems: architecture, parity and trade-offs · Published

A coverage table that says a component exists on every platform answers the first question an evaluator asks. It does not answer the second: does it behave the same? This guide describes a way to measure behavioural parity across platforms that stays honest as the code changes, using KinetixUI's own setup as the example. It assumes coverage itself is already checked against source; that half is about whether an implementation exists at all. This half is about what it has been shown to do.

Start by naming the kinds of evidence#

"Tested" hides too much. Split it into kinds that a reader can act on, each of which is either present for a component on a platform or not:

KindWhat it showsTypical instrument
BuildThe implementation compiles on its platformthe platform's own compiler in CI
InteractionBehaviour: keys, gestures, state changesunit or UI tests on that platform
AccessibilityWhat assistive technology is told: roles, names, statesARIA assertions, axe; SwiftUI traits; Compose semantics; Flutter semantics
RTLThe layout and the key handling mirrortests run under a right-to-left direction
Large textThe layout survives the platform's text-size settingtests at a large font scale
Reduced motionAnimation honours the platform setting and still reaches the final statetests with the setting on
VisualEach state looks as designedscreenshot comparison

A component on one platform can have interaction evidence and no RTL evidence. Keeping the kinds separate is what lets the report say so.

Derive the evidence from the tests#

The usual failure is a matrix someone fills in by hand. It is correct the day it is written and drifts toward optimism afterwards, because nobody removes a tick when a test is deleted.

KinetixUI avoids that by marking test passages instead of components. A test states what kind of check it performs, in a comment such as kx-verify: interaction, and a generator reads which components the passage covers from the KinetixUI symbols the passage actually calls. Three rules keep that from over-claiming:

  • A marker covers its passage, not its file. A long suite that checks right-to-left behaviour for three components reports RTL for three, not for every component the file mentions.
  • Coverage comes from code, never from a list. A marker cannot claim a component its passage does not exercise.
  • The result is generated and checked in CI. If the committed evidence file differs from a fresh run, the build fails, so nobody can edit a number by hand.

Report the weakest component, not the average#

Averages flatter. If nine components on a platform have accessibility tests and one does not, "90%" invites a reader to assume the one they need is covered. Instead, define levels by the evidence they require and give a platform's catalogue the level of its least-verified component. KinetixUI's levels are:

Verification levels
LevelEvidence required
experimentalBuild
betaBuild · Accessibility
stableBuild · Accessibility · Interaction · RTL · Large text · Visual · Published

and the result today, per platform, generated from the repository:

React

Implementations
98 of 98 · catalogue complete
Package maturity
stable
Distribution
npm
Catalogue verification
beta

Evidence

Build
98 / 98
Interaction
38 / 98
Accessibility
98 / 98
RTL
22 / 98
Large text
27 / 98
Visual
0 / 98
Published
98 / 98

98 beta. The catalogue figure above is the weakest of these, not an average.

Angular

Implementations
76 of 98 · catalogue incomplete
Package maturity
preview
Distribution
npm
Catalogue verification
preview

Evidence

Build
76 / 76
Interaction
76 / 76
Accessibility
76 / 76
RTL
43 / 76
Large text
49 / 76
Visual
0 / 76
Published
76 / 76

76 preview. The catalogue figure above is the weakest of these, not an average.

SwiftUI

Implementations
90 of 98 · catalogue complete
Package maturity
stable
Distribution
Swift Package Manager — not published
Catalogue verification
experimental

Evidence

Build
90 / 90
Interaction
0 / 90
Accessibility
0 / 90
RTL
0 / 90
Large text
0 / 90
Visual
0 / 90
Published
0 / 90

90 experimental. The catalogue figure above is the weakest of these, not an average.

Jetpack Compose

Implementations
90 of 98 · catalogue complete
Package maturity
stable
Distribution
Maven Central — not published
Catalogue verification
experimental

Evidence

Build
90 / 90
Interaction
7 / 90
Accessibility
6 / 90
RTL
1 / 90
Large text
0 / 90
Visual
0 / 90
Published
0 / 90

84 experimental · 6 beta. The catalogue figure above is the weakest of these, not an average.

Flutter

Implementations
90 of 98 · catalogue complete
Package maturity
stable
Distribution
pub.dev — not published
Catalogue verification
experimental

Evidence

Build
90 / 90
Interaction
6 / 90
Accessibility
5 / 90
RTL
58 / 90
Large text
58 / 90
Visual
0 / 90
Published
0 / 90

85 experimental · 5 beta. The catalogue figure above is the weakest of these, not an average.

Individual components often sit above their platform's floor, and each KinetixUI component page shows its own evidence per platform. The floor is what you can rely on without looking.

Keep three questions apart#

Evidence answers one question. Two others are often folded into it, and each makes the report less useful:

  • Availability: is there an implementation on this platform at all, or a documented alternative?
  • Package maturity: is this platform's package a finished product with a settled API?
  • Verification: what do the tests show about this implementation?

A package can be published and immature, or unpublished and well tested. Supported platforms keeps them in separate columns for that reason.

Prove each check can fail#

A gate that never goes red proves nothing about the defect it was written for. For each important check, run a negative control:

  1. Establish the broken condition, or reintroduce the original bug.
  2. Run the gate and confirm it fails with the expected rule.
  3. Restore the fix, confirm the file is byte-identical to before, and confirm the gate passes again.

KinetixUI keeps these as scripts next to its gates, and a control the gate no longer catches fails the script, so a check that has quietly stopped detecting anything shows up the next time the controls run. The habit matters more than the tooling: a check written after a real bug, and proven against that bug, is worth more than ten written against hypotheticals.

Know what each instrument cannot see#

Every kind of evidence has a blind spot, and the report should say which:

  • A unit test in jsdom proves roles, names and key handling. It does no layout, so it proves nothing about what a page looks like.
  • Mocked geometry proves the component's logic, not the browser's.
  • An axe pass proves what axe can detect, on the states it was shown.
  • A structural RTL check proves that the right properties are used, not that every screen looks right mirrored.
  • None of it is an audit by people using assistive technology.

KinetixUI's Accessibility page states which of these back each claim, and RTL does the same for direction.

Where to start#

If you have nothing yet, start with build evidence on every platform and accessibility evidence on the components people use most, mark passages rather than components, generate the report, and publish the weakest-component figure even when it is low. The low number is the useful one: it tells you where the next test goes. The wider context, including where parity tends to break first, is in Cross-platform design systems: architecture, parity and trade-offs.

View verification evidence