Mobile
Parity with the web
What exists in React Native, and how each component differs from its web twin.
What runs in React Native, from @krizaka/ui/native. Most components exist on both platforms with the same name and the same props; a few exist only on mobile, because the platform asks for them (a tab bar, a sheet, a pull to refresh).
58 components on both platforms, 15 on mobile only, 83 on the web only.
| Web | Mobile | What differs on mobile | |
|---|---|---|---|
| Action sheet | — | Yes | Mobile only |
| Activity feed | Yes | Yes | A SectionList with sticky day headings; live announces through the platform. No Timeline yet: use Stepper for a history on a phone. |
| Area chart | Yes | Yes | No data table or export: the summary is the accessible label, swipe up and down to hear each week. A tap selects the nearest point; no hover. |
| Avatar | Yes | Yes | The fallback is the initial of alt when fallback is not given. size also takes a number of points. src is a URI string (an Image source), not a URL object. An SVG src (….svg, data:image/svg+xml,…, or any URI with svg) is drawn by react-native-svg — Image cannot. presence adds a dot (online, away, busy, offline) and ring a story ring (new, seen, live): mobile only for now. |
| Badge | Yes | Yes | The text is set in capitals by the component. No className: style it with style. |
| Bar chart | Yes | Yes | Vertical bars only (no horizontal), no value labels at the tips. No data table or export: swipe up and down on the chart to hear each category. |
| Button | Yes | Yes | The text is the label prop (a string), not children: it is also the accessible name. onPress instead of onClick (a Pressable); haptics, if any, belong to your onPress. icon places an icon before the label; there is no asChild. loading shows the platform's ActivityIndicator in place of the icon. variant="gradient" draws its fill with react-native-svg (React Native has no CSS gradient). |
| Card | Yes | Yes | onPress on Card.Root makes the whole card a button (no asChild, no interactive). Built on View, Image and Text: style with style, not className. No Card.Stat and no reveal. |
| Charts provider | Yes | Yes | Also takes scheme and theme (the app's roles); no useSlidingWindow export on native. |
| Chat | Yes | Yes | The composer keeps clear of the home indicator; the send button plays a light tap. A failed bubble is itself the retry button. ConversationItem takes presence (a dot on the avatar) instead of online. |
| Checkbox | Yes | Yes | Always a 44-pt row: the box and its words, pressed as one; error shows under it (no Field around it). checked is true or false (no indeterminate); label names it when the words are a sentence with links. |
| Chip | Yes | Yes | The group's name is aria-label (not label). scrollable makes the group one horizontal row: a filter bar. onPress semantics: a chip alone is a checkbox, in a single group a radio. |
| Combobox | Yes | Yes | A field that opens a Sheet with a search box and the matching options: radios for one value, checkboxes and a Done button with multiple. onSearch(query, signal) is debounced (250 ms) and aborted by a newer query, as on the web; no creatable yet. |
| Countdown | Yes | Yes | Same props and same clock as the web; style with style. useCountdown and splitDuration are exported for a custom layout. |
| Credit usage | Yes | Yes | No description, loading or className: lay it out with style. The daily use is a native sparkline, read as one element. |
| Date picker | Yes | Yes | No popover field (DatePicker, DateRangePicker): on a phone, the Calendar, the DayStrip or the wheels sit in the screen or in a Sheet. DateField is typed (day · month · year, numeric keypads); DateWheel is the same date as three wheels — the native form's DateField uses the wheels. Each value a wheel passes, each day or slot pressed plays a selection haptic — when the app passes haptics to the ThemeProvider (expo-haptics): the platform has no native module. A wheel is an adjustable control for VoiceOver and TalkBack (swipe up or down), named by its label, its value read as words. |
| Description list | Yes | Yes | term is a string; layout="grid" draws two cards per row. No KeyValueGrid: use layout="grid". |
| Dialog | Yes | Yes | One component, Sheet: a bottom sheet on React Native's Modal (focus kept inside, the back button and the scrim close it), its grip on top, rising with the theme's ease. It holds what a phone shows over a screen: a choice (Select, Combobox use it), the details of a pin on a map, a short form. |
| Earnings chart | Yes | Yes | The total and the change sit above the chart as a headline (the first thing a phone shows), not in the description. No data table or export: swipe on the chart to hear each period. |
| Empty state | Yes | Yes | The action is a native Button (with label). Style with style, not className. |
| Field | Yes | Yes | One component, TextField: the label, the input, the hint or the error together (no Field.* parts, no htmlFor). Every TextInput prop passes through (secureTextEntry, keyboardType, autoComplete, returnKeyType); multiline is the text area; onValueChange gives the text. end holds an adornment (a spinner, a check, a show-password button); inputRef focuses the input. A choice among many is Select: a field that opens a Sheet of options. |
| Floating action button | — | Yes | Mobile only |
| Form | Yes | Yes | Import createKrizakaForm from @krizaka/ui/native/form: the same definition (schema, defaults, i18n), the same useForm, form.* fields drawn with the native ones. form.Form is a View; form.Submit takes label and announces the first error of a refused submit (no focus to move). DateField is three wheels by default (entry="parts": typed day · month · year); RadioGroup has the native looks (variant list · cards · buttons · segmented); Select and Combobox open a Sheet; Switch is a settings row drawn by the theme; Slider floats its value; Money uses the decimal keypad. Each control plays its haptic when the app passes haptics to the ThemeProvider. No Combobox, TagInput, FileUpload or Slider field yet: a screen of its own (a picker) sets the value, or form.Field draws it. |
| Gauge | Yes | Yes | No zone bands around the arc: the value takes the zone's tone. The summary is the accessible label (no meter role in React Native). |
| Goal gauge | Yes | Yes | The steps light once on mount (animated), not on scroll. drain keeps the default look's final state: the spent steps do not fade on mobile, except in the arcade flavour. |
| Goal progress | Yes | Yes | timeLeft is a string (the app writes it); the facts are written under the gauge. |
| Header | — | Yes | Mobile only |
| Image viewer | — | Yes | Mobile only |
| Job throughput | Yes | Yes | The total and the success rate are a headline above the chart. No data table or export: swipe on the chart to hear each period. |
| Latency chart | Yes | Yes | Vertical bars only (no vertical prop): keep the names short. The slowest p95 is a headline above the chart. |
| Line chart | Yes | Yes | No data table or export: the plot is one adjustable element whose label is the title and the summary; swipe up and down to hear each point. A tap selects the nearest point and writes it under the chart; no hover. No markers, no end labels; scheme and theme (from @krizaka/ui/native's useTheme()) follow the app's theme. |
| List | Yes | Yes | Its own entry, @krizaka/ui/native/list (FlashList, an optional peer); rows are rendered by renderItem, not described by row. useInfiniteList loads the next page near the end and refreshes on a pull, through @krizaka/query. |
| Loader | Yes | Yes | product (orochia, orazaka, yazakia, yororis, krizaka) draws the product's animated ProductMark; on the web it is the mark slot. Announced with the platform's announcement (and a polite live region) instead of role="status". No LoadingRegion: lists show their own skeleton rows (List loading). overlay and page cover their parent with the theme's surface at 90 %; no backdrop blur. |
| Map | Yes | Yes | MapLibre Native (@maplibre/maplibre-react-native, an optional peer, with its Expo config plugin): the same style and tiles as the web — it reads pmtiles:// itself. A marker's details open in a Sheet (@krizaka/ui/native); markers and Near me play a haptic. Near me asks the system's permission through MapLibre's LocationManager when pressed; the app declares the location usage in its config. The map's name lists its places for VoiceOver and TalkBack; the screenshots of these stories are drawn by a stand-in (the markers placed, not the tiles). |
| Mascot state | Yes | Yes | title and description are strings; the action is a native Button. No framed and no titleAs: style with style. Only the idle bob and a fade-in: the web gestures (wave, dots, hop) stay on the web. |
| Mascots | Yes | Yes | Only the idle bob and the badges: the wave, the dots and the hop are web gestures. Style with style, not className. |
| Match dialog | Yes | Yes | Full screen; the avatars slide in with a spring, the heart pops. |
| Media capture | Yes | Yes | Its own entry, @krizaka/ui/native/media-capture, on expo-camera (an optional peer). facing is front or back; onCapture receives a file uri, not a blob; a refusal for good opens the Settings. mode is photo or video; labels is required. |
| Media picker | — | Yes | Mobile only |
| Meter | Yes | Yes | The parts' colours are the accent, then warning, success, secondary text and danger: apart in every brand. A group of parts is one element whose name lists each part and its value. |
| Number ticker | Yes | Yes | trigger is mount or change (a screen has no viewport to enter). variant and tone pick the type scale and the text role (Txt). |
| Onboarding | — | Yes | Mobile only |
| OTP input | — | Yes | Mobile only |
| Pagination | Yes | Yes | Folded only: previous / next and “Page 3 of 12”, the form a thumb reaches; no numbers, no links, no page size. labels is required (previous, next, compact). |
| Permission prompt | — | Yes | Mobile only |
| Photo grid | Yes | Yes | A tap or a long press opens the photo's menu (an ActionSheet) instead of drag and drop. |
| Pie and donut chart | Yes | Yes | No tooltip: swipe up and down on the chart to hear each slice and its share. No onSelect, no data table. |
| Price ticker | Yes | Yes | The current price and the change are a headline above the plot. No dots on the steps; no data table or export. |
| Profile card | Yes | Yes | name and caption are strings; no nameAs, no icon. One look: no arcade flavour on mobile. The gauges fill once on mount (animated), not on scroll. |
| Progress | Yes | Yes | The ring's centre is native text (Txt). Style with style, not className. |
| Pull to refresh | — | Yes | Mobile only |
| Radio group | Yes | Yes | One component with options (value, label, description, hint, disabled) and variant — no Item / Card / Button / Segment parts. Each press plays a haptic when the app passes haptics: impact for a tactile key, selection otherwise. error shows under the group and is announced. |
| Screen | — | Yes | Mobile only |
| Search field | Yes | Yes | No shortcut and no suggestions: the keyboard's search key submits, and results are a screen of their own. clearLabel is required; role="searchbox" names the input. cancelLabel with onCancel adds the platform's Cancel button beside the field. |
| Segmented | — | Yes | Mobile only |
| Skeleton | Yes | Yes | width and height are props (points or a percentage), not classes. |
| Slider | Yes | Yes | Drawn by the theme with a pan responder: drag anywhere on the track, the nearest thumb follows; a selection haptic at each step passed (the app's haptics). Each thumb is an adjustable control for VoiceOver and TalkBack: swipe up or down by a step, its value read as words. floatingValue shows the value over the thumb while it is dragged ("always": at rest too). |
| Sparkline | Yes | Yes | No threshold line. |
| Spinner | Yes | Yes | The platform's ActivityIndicator, in the accent. |
| Splash hand-off | — | Yes | Mobile only |
| Step progress | Yes | Yes | backLabel + onBack instead of a back node; it keeps clear of the status bar. |
| Stepper | Yes | Yes | statusLabels gives the words read after each step (the web hides them in the markup). A list of listitems, each named by its title and status. |
| Swipe deck | Yes | Yes | The card tilts with the finger and a stamp (LIKE / NOPE) says the decision; a medium tick marks it. PersonCard pages its photos with a tap on a side; screen readers swipe up and down. |
| Swipeable row | — | Yes | Mobile only |
| Switch | Yes | Yes | Drawn by the theme, not the system's: the same switch on iOS and Android, the accent when on, a selection haptic when it flips (the app's haptics). showLabel makes it a settings row: the label and its description beside the switch, the whole row pressable, the description read as the hint. error shows under the row and is announced. |
| Tab bar | — | Yes | Mobile only |
| Tabs | Yes | Yes | items (value, label, count, content) instead of the web's parts. The underlined tab list scrolls sideways when it does not fit; for the app's main sections use TabBar. |
| Tag selector | Yes | Yes | A selection tick on each toggle. |
| Theme | Yes | Yes | ThemeProvider takes the product's colour roles (overrides) and fonts; there is no ThemeScript and no toggle. useTheme() returns the resolved theme (colour roles), scheme, radius and motion for StyleSheet. The mode is not persisted: the app stores it from onModeChange. |
| Toast | Yes | Yes | Toaster takes offset (the safe-area inset) instead of a position; mount it inside ThemeProvider. Actions take onPress; a toast takes onPress to open what it is about. No toast.custom: an icon before the text instead. A sideways swipe dismisses a toast; its tone plays a haptic when the app gives haptics. A snackbar is Toaster position="bottom" with one action. |
| Txt | — | Yes | Mobile only |
| Verified badge | Yes | Yes | size is in points; on="media" instead of onMedia. |
| Video player | Yes | Yes | Its own entry, @krizaka/ui/native/video-player, on expo-video (an optional peer): an app that plays no video installs nothing. The platform's controls (nativeControls, default true): accessible, full screen and picture in picture by the system. source is an object (uri, contentType, headers); paused stops it off screen (a FlatList's viewability). |