# Cart screen

> A shopping cart: line items with a quantity stepper whose minus turns into remove, swipe left to remove or save for later, a promo code field, a free delivery meter and totals that roll with every change above a checkout bar. Removing an item offers Undo; an empty cart shows its own empty state.

- Type: Component (screens)
- Access: Pro
- Page: https://goodui.dev/native/components/cart-screen
- Markdown: https://goodui.dev/native/components/cart-screen.md
- Registry item: https://goodui.dev/native/r/cart-screen.json
- Dependencies: react-native-reanimated, react-native-svg
- Keywords: react native cart screen, shopping cart expo, swipe to delete cart item, promo code field, free shipping progress, ecommerce checkout bar, empty cart state

## When to use

- The cart or basket of a shop, grocery or food ordering app before checkout.
- Any list of things being bought where quantities and a running total matter.

## When not to use

- Picking delivery and paying: use checkout-screen after this one.
- A wishlist without quantities or totals: use list-row rows with swipe-actions.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add @goodui-native-pro/cart-screen
npx expo install --fix
```

Pro: add `"@goodui-native-pro": { "url": "https://goodui.dev/native/r/pro/{name}.json", "headers": { "Authorization": "Bearer ${GOODUI_LICENSE_KEY}" } }` to the `registries` of components.json and put your license key in .env.local.

The component lands in `components/goodui-native/cart-screen/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs button, chip, empty-state, icon-button, locale, quantity-stepper, rolling-number, swipe-actions, text-field, toast.

### Setup

- Wrap the app in GestureHandlerRootView and ThemeProvider, and render <Toaster /> once for the Undo toast.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
// app/cart.tsx
import { Stack, router } from "expo-router";
import { CartScreen } from "@/components/goodui-native/cart-screen/cart-screen";
import { api, useCart } from "@/lib/cart";

export default function CartRoute() {
  const cart = useCart();
  return (
    <>
      <Stack.Screen options={{ headerShown: false }} />
      <CartScreen
        items={cart.items} // [{ id, title, variant, price, quantity, image }]
        onItemsChange={cart.setItems}
        currency="EUR"
        shippingFee={4.9}
        freeShippingOver={100}
        onApplyPromo={(code) => api.checkPromo(code)} // resolve { code, label, percentOff } or reject new Error("message")
        onCheckout={(summary) => router.push("/checkout")}
        onSaveForLater={(item) => api.saveForLater(item.id)}
        onBrowse={() => router.push("/shop")}
        onBack={() => router.back()}
      />
    </>
  );
}
```

## Examples

### On its own, with sample items (try the code WELCOME10)

```tsx
<CartScreen />
```

### Always charge delivery, no undo toast

```tsx
<CartScreen items={items} onItemsChange={setItems} freeShippingOver={Infinity} undo={false} />
```

## API reference

### CartScreen

`import { CartScreen } from "@/components/goodui-native/cart-screen/cart-screen";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `CartItem[]` | – | Items (controlled). Pair with `onItemsChange`. |
| `defaultItems` | `CartItem[]` | `defaultItems` | Starting items when uncontrolled. |
| `onItemsChange` | `(items: CartItem[]) => void` | – | Called with the new list after a quantity change or a removal. |
| `currency` | `string` | `"EUR"` | ISO 4217 code for every amount. Default "EUR". |
| `shippingFee` | `number` | `4.9` | Delivery fee below `freeShippingOver`. Default 4.9. |
| `freeShippingOver` | `number` | `100` | Subtotal (after discount) from which delivery is free. Default 100. Pass `Infinity` to always charge. |
| `onApplyPromo` | `(code: string) => Promise<CartPromo>` | `defaultApplyPromo` | Check a promo code. Resolve with the promo, or reject with an Error whose message is shown under the field. |
| `defaultPromo` | `CartPromo \| null` | `null` | Promo applied when the screen opens. |
| `onCheckout` | `(summary: CartSummary) => unknown` | – | Checkout button. Receives the totals. Return a promise to show a spinner on the button. |
| `onSaveForLater` | `(item: CartItem) => void` | – | The second swipe action, "Save for later". Hidden when omitted. The item leaves the cart. |
| `onBrowse` | `() => unknown` | – | Empty state action, for example navigating to the shop. |
| `onBack` | `() => void` | – | Back button. Hidden when omitted. |
| `undo` | `boolean` | `true` | Undo toast after a removal. Default `true`; needs the Toaster at the app root. |
| `locale` | `string` | – | BCP 47 locale for amounts. Defaults to the device locale. |
| `labels` | `Partial<CartScreenLabels>` | – | Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- 'Cart' is the header with the item count next to it.
- Each row's stepper is adjustable and named 'Quantity, <title>'; at one, minus becomes a labelled remove button.
- Swipe actions are also screen reader actions on the row (Remove, Save); a removal is announced, and Undo is in a toast.
- The promo field announces its error under the field; an applied code is announced and shown as a chip with a remove button.
- Totals are read as plain numbers; the free delivery line is visible text ('Add €12.40 more for free delivery').

## Motion

- Every total rolls: the line price when its quantity changes, the subtotal, discount, delivery and total, and the checkout bar.
- The free delivery meter fills on the smooth spring and turns green when the order qualifies.
- Swipe left: the actions unfold with the finger; a long swipe removes, the row slides out and collapses, and the rows below close the gap on the smooth spring.
- A wrong code shakes the field and slides the error in; a good one swaps the field for the code chip.
- Reduced motion: digits change in place, the meter jumps, rows close the gap at once, and the field does not shake.

## Haptics

- tick on each quantity step, delete when the trash removes the item, warning at the limits (QuantityStepper)
- select when a swipe crosses the full-swipe threshold, delete when the remove action runs (SwipeActions); notify for the toast, undo on its Undo
- tap on Apply and Check out, success or error when Apply settles (Button); error when the field shows an error (TextField)
- tap on removing the promo chip

## Performance

- Quantities, swipes and rolls animate on the UI thread; React renders on item, promo and keyboard changes.
- Rows render in a ScrollView: built for the tens of items a cart holds.

## Notes for AI

- Controlled: pass items and onItemsChange (called after every quantity change and removal). Uncontrolled: pass defaultItems.
- onApplyPromo resolves with { code, label, percentOff } or { code, label, amountOff }, or rejects with an Error whose message is shown under the field. The default accepts WELCOME10 only, for previews.
- Delivery is free when the subtotal after discount reaches freeShippingOver; pass Infinity to always charge shippingFee.
- The Undo toast needs <Toaster /> once at the app root; pass undo={false} if you have no Toaster.
- Render it full-bleed with the navigator header hidden (headerShown: false). It handles the safe areas and lifts the promo field above the keyboard on native, hiding the checkout bar while typing.

## Related

- [Checkout screen](https://goodui.dev/native/components/checkout-screen.md): The last step before paying: delivery address and payment method pickers, delivery options, the order summary with totals that roll when the delivery changes, and slide to pay in thumb reach. Paying covers the screen with a success check and confetti, then hands over through onDone.
- [Product screen](https://goodui.dev/native/components/product-screen.md): A shop's product detail: swipeable gallery with page pills, title, rating and a price that rolls with the size, color swatches or chips, size chips, a quantity stepper, specs, a reviews summary and a bottom bar with the rolling total. When Add to cart succeeds the product photo flies in an arc into the cart button and its count pops.
- [Quantity stepper](https://goodui.dev/native/components/quantity-stepper.md): A − value + stepper whose value rolls in the direction of change. Hold a button to repeat with acceleration; the ends push back with a rubber-band bounce and a warning haptic. In a cart the − turns into a trash button at the minimum.
- [Swipe actions](https://goodui.dev/native/components/swipe-actions.md): Row actions that unfold with the finger; a long swipe lets the edge action take over and run, and destructive actions collapse the row before it leaves.
- [Rolling number](https://goodui.dev/native/components/rolling-number.md): A number whose digits roll in the direction of change, with digits that open and close in place and currency signs that glide instead of jumping.
- [Empty state](https://goodui.dev/native/components/empty-state.md): A designed empty, error or offline state: a tinted disc pops in, its line art draws itself stroke by stroke with the highlight landing last, then the title, description and actions rise in.

## Guidance for AI tools

Cart screen: A shopping cart: line items with a quantity stepper whose minus turns into remove, swipe left to remove or save for later, a promo code field, a free delivery meter and totals that roll with every change above a checkout bar. Removing an item offers Undo; an empty cart shows its own empty state. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
