Skip to content

@gj-kit/expo-ui core concepts

React Native and web primitives: an unnamed IconButton, Tabs, or Slider is a compile error.

In a React Native design system the failures are silent: an IconButton ships with no accessibility label, a Tabs value is typo’d so the panel renders blank, an EmptyState action renders a button whose onPress was never wired, and a hand-assembled theme object leaks undefined into a style prop. None of that fails the build — it fails on a screen reader, in production, on someone else’s device.

Accessibility is part of the component contract

Section titled “Accessibility is part of the component contract”

Accessible names, press handlers, and range labels are required by component types, not left as a review checklist after layout work.

Tabs carry literal item values through to their panels, so a missing panel becomes a type error instead of an empty screen.

  • Measured Android popup coordinates — Android anchored Menu and Select measure root-relative trigger page coordinates to match the full-window Modal. Status-bar insets are not hardcoded; iOS and web retain their existing placement paths.
  • Accessible names the type demands — IconButton without accessibilityLabel, a rich-children Button with no name, and a range Slider given one label instead of a two-thumb tuple are all rejected.
  • Dead buttons do not compile — ButtonInteractionProps is a union: onPress is required unless disabled or loading is literally true, and an EmptyState action must carry both label and onPress.
  • Tabs cannot lose a panel — panels is typed Readonly<Record<NoInfer<ItemValue>, NonNullable<ReactNode>>> and value is NoInfer-wrapped, so a typo’d value, a missing panel, and a null panel all fail typecheck.
  • createTheme is the only door — UiProvider’s theme prop accepts only a branded Theme or ThemePair produced by createTheme or createThemes; a hand-assembled token object is a compile error.
  • No design literals in the source — A guard test walks every .tsx file under src/components recursively and fails on any quoted hex color, any numeric fontSize, or any quoted numeric fontWeight.

Keep optional safe-area and React Native Web peers behind their documented subpaths. Supply application copy through strings rather than baking product copy into primitives.

Continue with the two verified recipes.