Browse React Native
React NativeComponentsNo. 09 of 22
Empty State
What a screen shows when there is nothing yet: an icon, a heading, a line about what to do and actions, with or without a dashed border.
For the web: Empty State, with the same name and variants.
Preview
Loading the preview
The gallery's web build, through react-native-web. On a phone the same code draws native views.
Installation
npx shadcn@latest add @corsair-native/empty-stateThe app's components.json needs the @corsair-native registry first; see Installation. The files land in your project as source: edit them like your own code.
API
Read from the source's own comments and types. Props marked * are required.
EmptyStateComponent
What a screen shows when there is nothing to list yet: an icon, a title that says what is missing, a line about what to do, and actions. Compose it from EmptyStateIcon, EmptyStateTitle, EmptyStateDescription and EmptyStateActions.
| Prop | Type | Default |
|---|---|---|
variant
| "dashed" | "plain" | "dashed" |
ref | Ref<View> | — |
Also takes every ViewProps prop (React Native docs).
<EmptyState>
<EmptyStateIcon>{({ color, size }) => <CalendarX color={color} size={size} />}</EmptyStateIcon>
<EmptyStateTitle>No games this week</EmptyStateTitle>
<EmptyStateDescription>Book a court and invite your crew.</EmptyStateDescription>
<EmptyStateActions><Button>Find a court</Button></EmptyStateActions>
</EmptyState>EmptyStateIconComponent
A 48 px circle around a 24 px icon. Decorative: hidden from screen readers.
| Prop | Type | Default |
|---|---|---|
childrenAn icon, or a function that gets the muted colour and a 24 px size. | ReactNode | ((props: { color: string; size: number }) => ReactNode) | — |
ref | Ref<View> | — |
Also takes every ViewProps prop (React Native docs).
EmptyStateTitleComponent
Also takes every TextProps prop (from text).
EmptyStateDescriptionComponent
Also takes every TextProps prop (from text).
EmptyStateActionsComponent
| Prop | Type | Default |
|---|---|---|
ref | Ref<View> | — |
Also takes every ViewProps prop (React Native docs).
Compatibility
- Expo SDK
- 54 and 57, both checked in CI
- React Native
- 0.81 and 0.86, New Architecture
- Web
- Expo's web target, through react-native-web
Source
1 file, installed as source you own
empty-state.tsxView on GitHubimport type { ReactNode, Ref } from "react";
import { StyleSheet, View, type ViewProps } from "react-native";
import { useTheme } from "@/registry/native/lib/theme";
import { Text, type TextProps } from "@/registry/native/ui/text";
type PartProps = ViewProps & { ref?: Ref<View> };
interface EmptyStateProps extends PartProps {
/** `dashed` draws a dashed border around it; `plain` has none. */
variant?: "dashed" | "plain";
}
/**
* What a screen shows when there is nothing to list yet: an icon, a title
* that says what is missing, a line about what to do, and actions. Compose it
* from EmptyStateIcon, EmptyStateTitle, EmptyStateDescription and
* EmptyStateActions.
*
* @example
* <EmptyState>
* <EmptyStateIcon>{({ color, size }) => <CalendarX color={color} size={size} />}</EmptyStateIcon>
* <EmptyStateTitle>No games this week</EmptyStateTitle>
* <EmptyStateDescription>Book a court and invite your crew.</EmptyStateDescription>
* <EmptyStateActions><Button>Find a court</Button></EmptyStateActions>
* </EmptyState>
*/
function EmptyState({ variant = "dashed", style, ...props }: EmptyStateProps) {
const { colors, radius } = useTheme();
return (
<View
style={[
styles.root,
{ borderRadius: radius.lg },
variant === "dashed"
? { borderWidth: 1, borderStyle: "dashed", borderColor: colors.border }
: null,
style,
]}
{...props}
/>
);
}
interface EmptyStateIconProps extends Omit<PartProps, "children"> {
/** An icon, or a function that gets the muted colour and a 24 px size. */
children?: ReactNode | ((props: { color: string; size: number }) => ReactNode);
}
/** A 48 px circle around a 24 px icon. Decorative: hidden from screen readers. */
function EmptyStateIcon({ style, children, ...props }: EmptyStateIconProps) {
const { colors } = useTheme();
return (
<View aria-hidden style={[styles.icon, { backgroundColor: colors.muted }, style]} {...props}>
{typeof children === "function"
? children({ color: colors.mutedForeground, size: 24 })
: children}
</View>
);
}
function EmptyStateTitle({ style, ...props }: TextProps) {
const { text, font } = useTheme();
return (
<Text role="heading" style={[text.lg, font("semibold"), styles.title, style]} {...props} />
);
}
function EmptyStateDescription({ style, ...props }: TextProps) {
return <Text variant="muted" style={[styles.description, style]} {...props} />;
}
function EmptyStateActions({ style, ...props }: PartProps) {
return <View style={[styles.actions, style]} {...props} />;
}
const styles = StyleSheet.create({
root: {
alignItems: "center",
justifyContent: "center",
gap: 8,
padding: 32,
},
icon: {
width: 48,
height: 48,
borderRadius: 24,
alignItems: "center",
justifyContent: "center",
marginBottom: 8,
},
title: {
textAlign: "center",
letterSpacing: -0.45,
},
description: {
textAlign: "center",
maxWidth: 384,
},
actions: {
flexDirection: "row",
flexWrap: "wrap",
alignItems: "center",
justifyContent: "center",
gap: 8,
marginTop: 16,
},
});
export {
EmptyState,
EmptyStateActions,
EmptyStateDescription,
EmptyStateIcon,
EmptyStateTitle,
type EmptyStateProps,
};