Banner
Contextual notification banner with tinted backgrounds, optional icon, action button, and dismiss. Each variant has distinct colors that work in both light and dark mode.
New version available. Update now for the latest features.
import { Banner } from "@/components/ui/banner";
<Banner variant="info" onDismiss={() => {}}>
New version available. Update now for the latest features.
</Banner>Installation
npx @aniui/cli add bannerVariants
Each variant uses a unique tinted background with matching border and text color. Warning uses amber tones, success uses green, destructive uses red, and info uses your primary color.
Default banner message
Informational update
Please review your settings
Action required immediately
Operation completed successfully
<Banner variant="default">Default banner message</Banner>
<Banner variant="info">Informational update</Banner>
<Banner variant="warning">Please review your settings</Banner>
<Banner variant="destructive">Action required immediately</Banner>
<Banner variant="success">Operation completed successfully</Banner>With Action
Add an action prop with a label and onPress handler to show an inline action button.
A new version is available.
<Banner
variant="info"
action={{ label: "Update", onPress: () => {} }}
onDismiss={() => {}}
>
A new version is available.
</Banner>Props
PropTypeDefault
variant"default" | "info" | "warning" | "destructive" | "success""default"childrenstring—The banner message text.
iconReactNode—Optional leading icon. Pair with your preferred icon library.
action{ label: string; onPress: () => void }—Inline action button with label and press handler.
onDismiss() => void—Shows a dismiss button when provided.
classNamestring—Additional NativeWind classes for the container.
Source
components/ui/banner.tsx
import React from "react";
import { View, Text, Pressable } from "react-native";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const bannerVariants = cva(
"flex-row items-center rounded-xl px-4 py-3 gap-3 border",
{
variants: {
variant: {
default: "bg-secondary/60 border-border",
info: "bg-primary/8 border-primary/15",
warning: "bg-yellow-50 border-yellow-200 dark:bg-yellow-950/30 dark:border-yellow-900/40",
destructive: "bg-destructive/8 border-destructive/15",
success: "bg-green-50 border-green-200 dark:bg-green-950/30 dark:border-green-900/40",
},
},
defaultVariants: { variant: "default" },
}
);
const bannerTextVariants = cva("text-sm font-medium", {
variants: {
variant: {
default: "text-foreground",
info: "text-primary",
warning: "text-yellow-800 dark:text-yellow-200",
destructive: "text-destructive",
success: "text-green-800 dark:text-green-200",
},
},
defaultVariants: { variant: "default" },
});
export interface BannerProps
extends React.ComponentPropsWithoutRef<typeof View>,
VariantProps<typeof bannerVariants> {
className?: string;
children: string;
icon?: React.ReactNode;
action?: { label: string; onPress: () => void };
onDismiss?: () => void;
}
export function Banner({
variant,
className,
children,
icon,
action,
onDismiss,
...props
}: BannerProps) {
return (
<View
className={cn(bannerVariants({ variant }), className)}
accessibilityRole="alert"
{...props}
>
{icon}
<Text className={cn(bannerTextVariants({ variant }), "flex-1")}>
{children}
</Text>
{action && (
<Pressable
onPress={action.onPress}
accessible={true}
accessibilityRole="button"
className="min-h-8 min-w-8 items-center justify-center"
>
<Text
className={cn(
bannerTextVariants({ variant }),
"font-semibold underline"
)}
>
{action.label}
</Text>
</Pressable>
)}
{onDismiss && (
<Pressable
onPress={onDismiss}
className="ml-1 min-h-8 min-w-8 items-center justify-center rounded-lg"
accessible={true}
accessibilityRole="button"
accessibilityLabel="Dismiss"
>
<Text
className={cn(
bannerTextVariants({ variant }),
"text-base opacity-60"
)}
>
×
</Text>
</Pressable>
)}
</View>
);
}