Skip to content
Expo Development Foundation
Esc
navigateopen⌘Jpreview
On this page

Dynamic Island banner

Reusable in-app notification banner primitive (expo-dynamic-island).

expo-dynamic-island is a neutral, reusable Dynamic Island–style transient in-app notification banner for Expo apps (iOS, Android, Web): a provider with a Skia goo morph, swipe-to-dismiss gesture, sticky notifications, and a custom render override.

It is an external reusable primitive, not a vendored foundation skill — see External skills. Route banner work to it through $expo-development-foundation (Tree 3, UI stack), composed with expo-native-ui / expo-a11y as matched and closed with expo-verify.

When to use

  • Transient in-app card (download complete, upload progress, background work).
  • OS-level push or local scheduled delivery → use the expo-notifications skill instead; permission timing alone → expo-permissions.

Install

Install the Expo SDK 57 peers, then wrap the root layout with the provider (GestureHandlerRootViewSafeAreaProviderDynamicNotifications):

npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context expo-blur expo-image expo-symbols
import { DynamicNotifications } from "expo-dynamic-island";

export default function RootLayout() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <SafeAreaProvider>
        <DynamicNotifications>
          <Stack screenOptions={{ headerShown: false }} />
        </DynamicNotifications>
      </SafeAreaProvider>
    </GestureHandlerRootView>
  );
}

Trigger from any component inside the provider:

const { trigger, dismiss } = useDynamicNotifications();
trigger({ title: "Download complete", message: "Your file is ready" });

API essentials

  • trigger(notification): title (required), message?, avatar? (image URI), symbol? (SF symbol name), accent?, duration?, onPress?, render?.
  • duration={null} (provider or per notification) keeps the banner sticky until dismiss() is called.
  • render(notification) replaces the default card content entirely.
  • onDismiss(notification) on the provider observes dismissals.
  • Theming via cardColor, islandColor, accent, shadowColor.

Accessibility and platform notes

  • The card exposes an alert role with a title/message label; the default body is a single announcement.
  • With OS reduced motion on, the banner appears and dismisses without spring travel.
  • On Android and Web, expo-symbols glyphs fall back to no glyph — never rely on a symbol alone for critical meaning; prefer avatar, text, or render.
  • Title and message stay single-line truncated; custom render content is consumer-owned for Dynamic Type.

Verification

  • npx tsc --noEmit in the package.
  • npx expo-doctor in the consumer app.
  • Expo Go smoke: banner appears on trigger, auto-hides after duration, sticky hides only via dismiss(), tap fires onPress, render replaces card content, screen reader announces the alert.

Source

External reusable package expo-dynamic-island. The agent contract is SKILL.md at the package root; copy-paste consumer snippets live under example/. Ask the user for its checkout location rather than inventing one.

Stop rules

  • No EAS builds, submissions, or deployments by inference.
  • No secrets in code, config, or examples.

Was this page helpful?