Menu ordering components. Live demos use web counterparts; native code shown alongside.
_components/store-header.tsx
Default
Service fee will be applied to all orders
<View className="px-4 py-3">
<Text className="text-xl font-bold">{storeInfo.name}</Text>
<Text className="text-xs text-muted-foreground">
{storeInfo.address} · {storeInfo.distance}
</Text>
<View className="flex-row flex-wrap gap-1.5 mt-2">
{storeInfo.promos.map(p => (
<Badge key={p} variant="secondary">{p}</Badge>
))}
</View>
</View>_components/order-type-bar.tsx
Pickup active
Powered by DOORDASH
Delivery active
Powered by DOORDASH
<View className="flex-row gap-2 px-4 py-2">
{orderTypes.map(t => (
<Pressable
key={t.id}
className={cn(
"flex-1 items-center gap-1 rounded-lg py-2",
isActive ? "bg-foreground" : "border border-border"
)}
>
<t.icon className={cn("h-4 w-4", isActive ? "text-background" : "text-muted-foreground")} />
<Text className={cn("text-[10px] font-medium", isActive ? "text-background" : "text-muted-foreground")}>
{t.label}
</Text>
</Pressable>
))}
</View>_components/store-selector.tsx
Flaming Grill active
<ScrollView horizontal className="flex-row gap-2 px-4 py-2">
{stores.map(s => (
<Pressable
key={s.id}
className={cn(
"rounded-full px-4 py-1.5",
selected === s.id ? "bg-foreground" : "bg-muted"
)}
>
<Text className={cn("text-xs font-medium", selected === s.id ? "text-background" : "text-muted-foreground")}>
{s.name}
</Text>
</Pressable>
))}
</ScrollView>_components/category-tabs.tsx
Default
<View className="flex-row items-center gap-2 border-b px-4 py-2">
<Search className="h-4 w-4 text-muted-foreground" />
<ScrollView horizontal className="flex-row gap-4">
{categories.map((cat, i) => (
<Pressable key={cat} onPress={() => setSelected(i)}>
<Text className={cn("text-sm", selected === i ? "font-bold" : "text-muted-foreground")}>
{cat}
</Text>
</Pressable>
))}
</ScrollView>
</View>_components/menu-item-card.tsx
No quantity (add button)
Grilled chicken with teriyaki sauce
$6.55
With quantity
Premium beef with rice
$6.55
COMBO tag
Dish Summary or extra tex
$6.55
<View className="flex-row gap-3 px-4 py-3">
<Image source={item.image} className="h-20 w-20 rounded-lg bg-muted" />
<View className="flex-1 justify-between">
<Text className="text-sm font-semibold">{item.name}</Text>
<Text className="text-xs text-muted-foreground" numberOfLines={1}>{item.description}</Text>
<View className="flex-row flex-wrap gap-1 mt-1">
{item.tags.map(tag => <TagBadge key={tag} tag={tag} />)}
</View>
<Text className="text-sm font-semibold mt-1">${item.price.toFixed(2)}</Text>
</View>
{/* Add / QuantityStepper */}
</View>_components/cart-bar.tsx
With items
<View className="flex-row items-center justify-between border-t px-4 py-3">
<View className="flex-row items-center gap-2">
<ShoppingCart className="h-5 w-5" />
<Text className="text-base font-bold">${total.toFixed(2)}</Text>
<Text className="text-xs text-muted-foreground line-through">${originalTotal.toFixed(2)}</Text>
</View>
<Pressable className="rounded-full bg-destructive px-6 py-2">
<Text className="text-sm font-semibold text-destructive-foreground">Checkout</Text>
</Pressable>
</View>_components/bottom-nav.tsx
Order tab active
<View className="flex-row border-t">
{tabs.map(t => (
<Pressable key={t.id} className="flex-1 items-center gap-0.5 py-2">
<t.icon className={cn("h-5 w-5", isActive && "fill-current")} />
<Text className={cn("text-[10px]", isActive ? "font-bold text-foreground" : "text-muted-foreground")}>
{t.label}
</Text>
</Pressable>
))}
</View>