Success check
Free · MITReact Native · ExpoA success or error moment: the circle springs in, the check draws itself while a ring pulses out and the title rises in; the error variant draws a cross and shakes once. Inline or fullscreen, optionally with confetti.
Installation
$ npx shadcn@latest add https://goodui.dev/native/r/success-check.jsonThen run npx expo install --fix so react-native-reanimated, react-native-svg match your Expo SDK. Files land in components/goodui-native/success-check.
Usage
import { useState } from "react";
import { Button } from "@/components/goodui-native/button/button";
import { SuccessCheck } from "@/components/goodui-native/success-check/success-check";
export function SendMoney({ send }: { send: () => Promise<void> }) {
const [done, setDone] = useState(false);
return (
<>
<Button onPress={async () => { await send(); setDone(true); }}>Send $1,250.00</Button>
<SuccessCheck
variant="fullscreen"
visible={done}
onDismiss={() => setDone(false)}
title="Money sent"
subtitle="$1,250.00 to Maya Chen"
confetti
/>
</>
);
}When to use
- The end of a flow: payment sent, booking confirmed, account created, workout saved.
- A result that replaces a form or a sheet's content once it is submitted.
- A failed final step that needs a clear, calm error moment before offering a retry.
- A single button's result: Button and IconButton already show success and error themselves.
- Background events: use toast.
- A problem that leaves the screen usable: use banner.
Examples
Inline, replacing a sheet's form
{submitted ? (
<SuccessCheck title="Booked" subtitle="Thu 14 Nov, 10:30 with Dr. Patel">
<Button variant="secondary" onPress={close}>Done</Button>
</SuccessCheck>
) : form}Error, then retry
<SuccessCheck status="error" size="sm" title="Card declined" subtitle="Try another card" playKey={attempt} />API reference
| Prop | Type | Default |
|---|---|---|
| status `success` draws a check and pulses a ring; `error` draws a cross and shakes. | "success" | "error" | "success" |
| variant `inline` sits in your layout; `fullscreen` covers the screen through the portal and closes itself. | "inline" | "fullscreen" | "inline" |
| visible Plays the moment each time it turns `true`. Fullscreen closes with a fade when it turns `false`. Default `true`. | boolean | true |
| title One short line: "Payment sent", "Booked". Rises in under the mark. | string | — |
| subtitle Detail under the title: an amount, a time, a reference. | string | — |
| size Circle of 48, 72 or 96 pt. Default `md` inline, `lg` fullscreen. | "sm" | "md" | "lg" | — |
| playKey Change it to play the moment again without hiding it. | string | number | — |
| duration Fullscreen: milliseconds before `onDismiss` runs on its own. `Infinity` waits for a tap. Default 2200. | number | 2200 |
| onDismiss Fullscreen: called after `duration`, on a tap, on Escape or the Android back button. Set `visible` to false here. | () => void | — |
| confetti Burst confetti out of the circle on success. Default `false`. | boolean | false |
| haptic Success or error haptic as the mark lands. Default `true`. | boolean | true |
| children Extra content that rises in last, for example a Done button (inline) or a receipt line. | ReactNode | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<SuccessCheckLabels> | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- Success: the circle scales in on the bouncy spring, the check draws itself in (260 ms, from 170 ms), a ring pulses out to 1.75× and fades over 700 ms, then title, subtitle and children rise 12 pt on the smooth spring, staggered.
- Error: the circle scales in on the snappy spring, the two strokes of the cross draw one after another, then the mark shakes once.
- It plays again each time visible turns true, the status changes or playKey changes.
- Fullscreen fades its background in and out over the app.
- Reduced motion: circle and text fade in, the check appears complete, no ring, no shake, no confetti physics (Confetti shows its static sparkle).
- Haptic: success (celebrate with confetti) or error when the mark lands (about 400 ms in), once per play. haptic={false} turns it off.
- A handful of Reanimated values on the UI thread. Confetti mounts only when the burst fires and unmounts when it ends.
Accessibility
- Each time it plays it announces the title and subtitle (or 'Done' / 'Something went wrong').
- Fullscreen is modal (accessibilityViewIsModal): a single button that closes it on tap, with the hint 'Closes this message'; Escape on the web and the Android back button close it too.
- Colors come from success and danger with their on-colors; the mark is never the only signal when a title is set.
Notes for AI
- Inline: render it where the result belongs; visible={false} removes it. Fullscreen: control visible and set it false in onDismiss.
- Fullscreen closes after duration ms (default 2200); pass duration={Infinity} to wait for a tap.
- Use playKey to replay without hiding, for example the attempt number for repeated errors.
- children rise in last; inline that is the place for a Done button. In fullscreen the whole screen is already the close button, so pass text, not buttons.
Related
A celebration burst: paper pieces launch from a point or rain from the top on closed-form physics (air drag, gravity, sway), spinning and turning over as they fall; one burst per trigger, a static sparkle under reduced motion.
A press-responsive button with haptics that runs async actions on its own: it gathers into a spinner, then opens into a success or error state.
Background confirmations that stack at the top, fan out on tap, swipe away up or sideways, and pause their timers while touched.
An inline status banner that slides down from under the edge above and pushes the content down, flings away sideways with the finger, and can collapse on its own behind a draining hairline; includes an offline preset.