suiss/uim · Interaction

Top Banner

Short banners that slide in from the top of the screen, queue one at a time and can be swiped up to dismiss.

Top Banner is an open-source mobile interaction from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Top Banner on iOS in light mode

TopBannerProvider shows banners requested with show from useTopBanner. Each banner slides down below the top safe area with a title, an optional description, icon and action button, and hides after 4 seconds by default.

Banners queue and appear one at a time, with a short pause between them. Swiping a banner up past a small distance, or flicking it up, dismisses it; dragging pauses the timer. Use it for brief confirmations and status updates, such as a copied link or a restored connection.

Installation

$ pnpm dlx @esuiss/uim@latest add top-banner

The CLI also adds what it builds on: Button, Icon, Text.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-svg react-native-worklets
  1. Add the pieces it builds on: Button, Icon, Text, and the primitives components/primitives/portal.tsx.

  2. Copy the source into components/interactions/top-banner.tsx:

uniwind/components/interactions/top-banner.tsx
import { cn } from "cn"
import type { Icon as PhosphorIcon } from "phosphor-react-native"
import * as React from "react"
import { AccessibilityInfo, useWindowDimensions, View } from "react-native"
import { Gesture, GestureDetector } from "react-native-gesture-handler"
import {
  Easing,
  Keyframe,
  ReduceMotion,
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
  withTiming,
} from "react-native-reanimated"
import { useSafeAreaInsets } from "react-native-safe-area-context"
  1. Update the import paths to match your project.

Usage

import { TopBannerProvider } from "@/components/interactions/top-banner"
<TopBannerProvider>
  <Triggers />
</TopBannerProvider>

Wrap the app in TopBannerProvider, then call show({ title, description?, icon?, action?, timeout? }) from useTopBanner. show returns an id that you can pass to dismiss; calling dismiss() with no id dismisses the current banner.

icon is a Phosphor icon component. action is { label, onPress }; pressing it runs onPress and dismisses the banner. Pass a timeout of 0 or Infinity to keep a banner until dismissed.

Examples

Showing

A banner with a title and description, shown on mount.

iOS
Top Banner (showing) on iOS in light mode

With icon

A banner with a leading icon.

iOS
Top Banner (with icon) on iOS in light mode

With action

A banner with an action button.

iOS
Top Banner (with action) on iOS in light mode

Title only

A banner with only a title.

iOS
Top Banner (title only) on iOS in light mode

API Reference

TopBannerProvider

Holds the banner queue and renders the current banner in a portal.

PropType
About
Default time in milliseconds before a banner hides. Defaults to 4000.
Type
number
Default
4000
About
Classes for the banner card.
Type
string
Default
—
About
Name of a portal host to render into.
Type
string
Default
—
Type
React.ReactNode
Default
—

Accessibility

  • The banner has the alert role and is a polite live region.
  • A string title is announced when the banner appears.
  • The banner has a dismiss accessibility action.

Notes

  • Banners are up to 384 points wide and centered.
  • The card uses bg-surface-raised, or bg-surface-secondary in dark mode, with a border-separator outline; the icon uses text-link.
  • Slide animations respect the system reduce motion setting.