Skip to content
Native Animation
Rating sheet with a drawn face animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add rating-sheet-emoji-free
RatingSkia

Rating sheet with a drawn face

A rating sheet with a continuously changing face and configurable rating labels, feedback reasons, surface color, and fonts.

$9 for this animation

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

About this animation

A rating sheet with a continuously changing face and configurable rating labels, feedback reasons, surface color, and fonts.

Why this one

Five fixed emoji reactions turn feedback into five disconnected states. This face shares one continuous value with the slider: its mouth, eyes, blush, and color evolve under your finger. The expressions progress from a deep frown through a slight frown, a neutral mouth, and a gentle smile to an open smile with joyful curved eyes. No angled eyebrows compete with the expression. Submitting brings a small personal reaction and a drawn confirmation check. Reasons change with the rating, so the feedback stays relevant.

How it works

  1. Measure the container with onLayout; scale the face and slider from its width.
  2. Drive the radial gradient and custom facial paths from a single continuous Reanimated rating shared value. Skia updates on the UI thread.
  3. Compose pan and tap using Gesture.Exclusive. Drag anywhere along the track, then spring to the nearest integer with the release velocity.
  4. Notify React only when the rounded rating changes. Reveal the label after its text commits, and stagger reason chips by 40 ms.
  5. Blink on a cleaned-up 3–5-second timer. Submit once, bounce or nod, draw the Lucide check, and dismiss after 1,200 ms.
  6. Push the background back with scale, corner rounding, and opacity. The handle supports downward dragging and tap-to-dismiss.

Install

npx expo install @shopify/react-native-skia expo-linear-gradient react-native-gesture-handler react-native-reanimated react-native-worklets

Place the application inside GestureHandlerRootView. Load any custom fonts before rendering. For web, initialize CanvasKit with Skia's LoadSkiaWeb before importing the component; an existing Skia-enabled Expo application can use its current loader. Icons: Lucide (ISC). The copied paths in icons.ts come from the project's approved kit.

Usage

import { RatingSheetFace } from './rating-sheet-emoji-free';

export function Feedback() {
  return (
    <RatingSheetFace
      title="How was your order?"
      subtitle="Tell the team what stood out."
      onSubmit={(rating, reasons) => saveFeedback({ rating, reasons })}
    >
      <DeliveredOrder />
    </RatingSheetFace>
  );
}

Customize its personality and control it through a ref:

const feedback = useRef<RatingSheetFaceRef>(null);

<RatingSheetFace
  ref={feedback}
  initiallyOpen={false}
  initialRating={3}
  springDamping={28}
  autoCloseMs={1600}
  colorScheme="light"
  surfaceColor="#FFF8F1"
  fontFamily="Geist_400Regular"
  mediumFontFamily="Geist_500Medium"
  titleFontFamily="InstrumentSerif_400Regular"
  negativeReasons={['Temperature', 'Wait time']}
  positiveReasons={['Fast', 'Friendly', 'Great taste']}
/>

// From an event handler:
feedback.current?.open();
feedback.current?.setRating(5);

Import RatingSheetFaceRef from the same folder. Keep the reason list to two or three short strings for narrow phones. Supply five rating labels when localizing. The component imports no theme or catalog code; the demo passes its own fonts and brand copy.

Props

PropTypeDefaultDescription
childrenReactNode—Background application screen.
titlestringHow was your experience?Sheet heading.
subtitlestringYour feedback helps us improve.Supporting copy.
thankYoustringThank youConfirmation heading.
confirmationstringYour feedback has been sent.Confirmation detail.
submitLabelstringSubmitButton text.
initialRatingnumber2Initial rating, clamped to 1–5.
labelsfive-string tupleTerrible … Loved itText for each integer rating.
negativeReasonsreadonly string[]Slow service, QualityReasons below 4.
positiveReasonsreadonly string[]Fast, Friendly, Great qualityReasons at 4 or 5.
fontFamilystringsystemBody font.
mediumFontFamilystringbody fontControl font.
titleFontFamilystringsystemEditorial heading font.
colorSchemelight / dark / autoautoFollows device appearance by default.
surfaceColorstringlight/dark warm neutralSheet fill.
textColorstringlight/dark foregroundText and button fill.
initiallyOpenbooleantrueInitial sheet visibility.
springDampingnumber28Rating and entrance spring damping. Values below the damping needed for ζ ≥ 0.8 are raised to that minimum.
autoCloseMsnumber1200Delay between submit and dismissal.
onRatingChange(rating: number) => void—Integer transitions.
onSubmit(rating: number, reasons: string[]) => void—One submission per opening; only current reasons are included.
onClose() => void—Called after dismissal finishes.
accessibilityLabelstringRatingAdjustable control name.
styleStyleProp<ViewStyle>—Root style, including flex: 1.
testIDstring—Root test identifier.

The ref exposes open(), close(), reset(), submit(), and setRating(value, duration?). An optional duration sweeps continuously for scripted presentations; autoplay belongs to the demo.

Compatibility

Targets Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, and Skia 2.14.0. Uses the installed Expo Go-compatible modules; no additional native package is introduced. iOS, Android, and web are intended targets. This piece needs Skia-aware lazy registration in a web catalog.

Accessibility

The track is an adjustable control with the current rating, label, range, and increment/decrement actions. Tapping the track is an alternative to dragging; tapping the handle dismisses the sheet. Reasons expose checkbox roles and checked states. Controls have at least 44-point hit areas, including the full-width slider hit zone. Background accessibility is hidden while the sheet is open.

Reduced motion replaces continuous expressions with integer expressions and a fade, removes blink, face tracking, jumps, nods, and sheet translation, and fades labels and chips without displacement. The confirmation is announced through a polite live region.

Demo timeline and layout

The Ember & Oat delivered-order screen uses the kit's flame tile and coffee, croissant, and cup-soda paths. The sheet's warm palette is independent of system appearance.

Autoplay resets at 120 ms, begins a continuous 2→5 sweep at 620 ms, reaches delight at 2,520 ms, submits at 3,320 ms, and begins dismissal 1,200 ms later. The cycle repeats every 5,800 ms. All demo timers are cleaned up.

At 390×844 the sheet begins at 0.38 H; at 320×694 it begins at 0.34 H to retain readable two-line supporting copy and touch targets. The face uses 0.40 W. The track centers at 0.75 H, reasons begin at 0.82 H, and Submit sits 18 points above the bottom. No demo control occupies the catalog viewer's top-right close area. Material effects use the face's radial shader and surface shadows, without a moving opaque overlay.