popapp
PopApp UI
A React Native component registry for Expo apps. Components are added as source code to the user's project via the CLI — like shadcn/ui, but for React Native with pure StyleSheet (no NativeWind, no Tailwind).
IMPORTANT: All CLI commands use
npx popapp. The CLI handles dependency resolution, import transformation, and file installation automatically.
Principles
- Use existing components first. Run
npx popapp listbefore writing custom UI. Check references/components.md for the full catalog. - Compose, don't reinvent. Settings screen =
Screen+List+Card. Onboarding flow =Onboarding+OptionGroup+Button. Dashboard =Screen+Card+Ticker+ProgressRing. - Use
useTheme()for all colors. Never hardcode hex values like#007AFF. Always pull from theme tokens. - Use semantic color tokens.
colors.destructivefor errors,colors.successfor confirmation — not raw color names.
Critical Rules
Styling — StyleSheet Only
PopApp uses StyleSheet.create() for static styles and inline theme colors. There is no className, no NativeWind, no Tailwind.
// CORRECT — static layout in StyleSheet, theme colors inline
const { colors } = useTheme();
<View style={[styles.container, { backgroundColor: colors.card }]}>
const styles = StyleSheet.create({
container: { padding: 16, borderRadius: 12 },
});
// WRONG — no className in React Native
<View className="bg-card p-4 rounded-xl">
Theme Access
Every component that uses color must call useTheme(). The hook returns { colors, colorScheme }.
import { useTheme } from "@/lib/theme/use-theme";
export function MyComponent() {
const { colors } = useTheme();
return <View style={{ backgroundColor: colors.background }} />;
}
Safe Wrappers for Optional Dependencies
Never import expo-haptics or expo-glass-effect directly — they may not be installed. Use the safe wrappers that gracefully no-op when the package is missing.
// CORRECT — safe wrappers
import { impactMedium } from "@/lib/haptics";
import { SafeGlassView, isGlassAvailable } from "@/lib/glass";
// WRONG — crashes if not installed
import * as Haptics from "expo-haptics";
import { GlassView } from "expo-glass-effect";
Component Composition
Components use named exports, not compound components. Import each piece separately.
// CORRECT
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
<Card>
<CardHeader>
<CardTitle>Settings</CardTitle>
</CardHeader>
<CardContent>
{/* content */}
</CardContent>
</Card>
// WRONG — no compound component pattern
<Card.Header>
<Card.Title>
Icons
Use IconSymbol with SF Symbol names. On iOS it renders native SF Symbols; on Android/web it maps to Material Icons automatically.
import { IconSymbol } from "@/components/ui/icon-symbol";
<IconSymbol name="heart.fill" size={24} color={colors.primary} />
For circular icon buttons use ActionIcon. For tinted category icons use ThemeIcon.
Component Selection
| Need | Use |
|---|---|
| Button / action | Button with variant prop (solid, outline, ghost, subtle, destructive) |
| Text inputs | TextInput, TextArea, OTPInput |
| Numeric input | InputStepper, SliderBar, RulerSlider |
| Selection (single/multi) | OptionCard + OptionGroup |
| Date input | DatePicker |
| Data display | Card, Badge, Ticker, ProgressRing, Markdown |
| Lists / settings | List with ListSection and ListCell |
| Screen layout | Screen with header, content, sticky button |
| Overlays / modals | BottomSheet |
| Loading placeholders | Skeleton |
| Icons | IconSymbol, ActionIcon (circular button), ThemeIcon (tinted circle) |
| Content transitions | AnimatedContent |
| Paging / carousel | Carousel |
| Onboarding flows | Onboarding system |
| Auth scaffold | auth-supabase template |
| Visual separators | Separator |
| Gradient edges | GradientTint utility |
Animation Tiers
Components declare their animation tier so you know what native dependencies they need:
| Tier | Dependencies | Examples |
|---|---|---|
| 1 | None (pure React Native) | Button, Card, TextInput, Badge, Separator, List |
| 2 | react-native-reanimated (ships with Expo) |
Touchable, Skeleton, ProgressRing, Ticker, Carousel |
| 3 | Reanimated + react-native-gesture-handler |
SliderBar, RulerSlider, BottomSheet |
Key Patterns
Screen layout with sticky button
import { Screen, ScreenContent, ScreenStickyButton } from "@/components/ui/screen";
<Screen>
<ScreenContent>
{/* scrollable content */}
</ScreenContent>
<ScreenStickyButton title="Continue" onPress={handleNext} />
</Screen>
Haptic feedback on interactions
import { impactMedium } from "@/lib/haptics";
const handlePress = () => {
impactMedium();
// ... action
};
Settings-style list
import { List, ListSection, ListCell } from "@/components/ui/list";
<List>
<ListSection header="Account">
<ListCell title="Profile" icon="person.fill" onPress={goToProfile} />
<ListCell title="Notifications" icon="bell.fill" toggle value={notifs} onValueChange={setNotifs} />
</ListSection>
</List>
Conditional glass effect
import { SafeGlassView, isGlassAvailable } from "@/lib/glass";
const content = <View style={styles.card}>{children}</View>;
if (glass && isGlassAvailable()) {
return <SafeGlassView style={styles.card}>{content}</SafeGlassView>;
}
return content;
Workflow
- Check setup — look for
popapp.jsonin the project root. If missing, runnpx popapp init. - Check installed components — list the
components/ui/directory to see what's already available. - Find components — run
npx popapp listto see all available registry items, or check references/components.md. - Add components —
npx popapp add button card screen. Dependencies are auto-resolved (e.g.,buttonalso installstheme,haptics,glass,touchable). - Import and use —
import { Button } from "@/components/ui/button". Make sure the app is wrapped inThemeProvider. - Customize theme — pass token overrides to
ThemeProvider:<ThemeProvider light={{ primary: "#6366F1", primaryForeground: "#fff" }} dark={{ primary: "#818CF8", primaryForeground: "#000" }} >
CLI Quick Reference
npx popapp init # Initialize project, install theme
npx popapp add button card screen # Add components (deps auto-resolved)
npx popapp list # List all available components
Flags:
--yes— skip confirmation prompts
Detailed References
- references/components.md — Full component catalog with props, dependencies, and tiers
- references/theme.md — Theme tokens, default values, and customization