Skip to main content
Lane GarnerWeb and Mobile Developer

tutti-ui

A cross-platform design system for React and React Native

At a glance

Role

Creator: design, API, web + native implementation, docs


Stack

  • TypeScript
  • React
  • React Native
  • Tailwind CSS
  • NativeWind
  • Storybook
  • Jest + Testing Library

Overview

tutti-ui is a design system that ships to both React and React Native from one set of design tokens: colors, spacing, typography, radii, and shadows defined once in @tutti-ui/tokens and consumed by a Tailwind preset on web and NativeWind classes on native. The name is a nod to my music background: tutti is the score marking for “everyone plays.”

It currently spans 32 component families (60+ exports) on web, with 27 of the 32 ported to React Native; the remaining five are web-idiom components (like Tooltip and CommandPalette) that map to different mobile patterns by design. The whole system is documented in a live Storybook, covered by 600+ Jest + Testing Library tests (332 web, 271 native), and written in strict TypeScript.

This portfolio is built with it: the buttons, cards, tabs, form fields, breadcrumbs, and theme provider on every page are @tutti-ui/react, themed through its Tailwind preset.

The tutti-ui logo and wordmark

Why cross-platform parity is the hard part

Most component libraries pick a platform. The interesting problems in tutti-ui came from refusing to: every component needed the same API, the same variants, and the same accessibility guarantees on two very different runtimes. A web Select is a native popup; on mobile it becomes a trigger plus bottom-sheet modal (same props, different idiom). Focus rings don't exist on native, so they're approximated with border treatments. ARIA roles map to accessibilityRole / accessibilityState.

The parity work is tracked publicly, component by component, in PARITY.md, including the honest “deferred” and “web-only by design” calls.

One token source, two renderers

// tailwind.config.ts
import { tuttiPreset } from "@tutti-ui/react/tailwind";

export default {
  presets: [tuttiPreset],
  darkMode: "class",
};

// Anywhere in the app
import { Button, Card } from "@tutti-ui/react";

Accessibility as the default

Every interactive component ships with keyboard navigation, visible focus states, and correct semantics on web, plus the equivalent accessibility props on native. The AI-native primitives (streaming text, chat, agent workflow states) handle screen-reader announcements and reduced motion from the start, because streaming UI is where accessibility usually falls apart.

Side-by-side: the same Card + Button rendered on web (Storybook) and iOS simulator (react-native)

Outcome

A production design system with a live Storybook, published npm packages (@tutti-ui/react, @tutti-ui/react-native, @tutti-ui/tokens, @tutti-ui/shared), and a real consumer: this site.


← All projects