# DetailPage component for Stripe Apps

Use DetailPage to implement detail-style layouts in Stripe Apps.

# v9


To add the `DetailPage` component to your app:

```js
import {DetailPage, PageModule} from '@stripe/ui-extension-sdk/ui';
```

Detail pages show a focused view of a single item, such as a customer, order, or subscription, along with its related objects and available actions. They serve as the destination when a user selects an item from a list view.

The `DetailPage` component provides a structured layout for detail-style pages in Stripe Apps. It renders a page header (with title, optional description, breadcrumb navigation, and action buttons) followed by a content area organized into a primary column and an optional secondary column. You compose content inside each column using `PageModule` components.

> `DetailPage` is a top-level page component. Don’t nest it inside a `FullPageView` because it manages its own page shell. Use it as the root component of your view when displaying a detail screen.

## When to use

Use a *single-column layout* when the detail view contains one content focus. This works well for:

- Simple object details, such as a profile or a configuration page
- Linear content that benefits from full-width reading
- Mobile-friendly layouts

Use a *two-column layout* when the object has both primary content and supporting context. This works well for:

- Customer detail pages with a main activity feed and a sidebar of metadata
- Order or invoice pages with line items on the left and a summary on the right
- Any detail view where users need quick access to related information while reviewing the primary content

## Layout structure

### DetailPage

`DetailPage` accepts the required `title` and `breadcrumbs` props, where `breadcrumbs` must include at least one item, and the optional `description`, `actions`, `primaryColumn`, and `secondaryColumn` props.

Both columns accept a single element or multiple elements using React Fragment:

```jsx
import {useNavigation} from '@stripe/ui-extension-sdk/navigation';
import {DetailPage, PageModule} from '@stripe/ui-extension-sdk/ui';

// Two-column layout
export function CustomerDetail() {
  const {createAppRoute} = useNavigation();

  return (
    <DetailPage
      title="Jenny Rosen"
      description="Pro plan customer since March 2022."
      breadcrumbs={[
        {
          type: 'link',
          label: 'Customers',
          route: createAppRoute('customers'),
        },
      ]}
      primaryColumn={
        <>
          <PageModule title="Payment history">
            <PaymentHistory />
          </PageModule>
          <PageModule title="Recent activity">
            <RecentActivity />
          </PageModule>
        </>
      }
      secondaryColumn={
        <>
          <PageModule title="Account details">
            <AccountDetails />
          </PageModule>
          <PageModule title="Active subscriptions">
            <Subscriptions />
          </PageModule>
        </>
      }
    />
  );
}

// Single-column layout (secondaryColumn omitted)
export function SimpleDetail() {
  return (
    <DetailPage
      title="Jenny Rosen"
      primaryColumn={
        <PageModule title="Overview">
          <Overview />
        </PageModule>
      }
    />
  );
}
```

You must wrap each column’s inner elements with `PageModule`.

### DetailPage props

| Property          | Type                                                                                                                                                                                                                                                                                     |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `breadcrumbs`     | (Required)
  `BreadcrumbLink[]`

  The breadcrumb items of the detail page. They’ll be displayed in the given order in the page header. Must contain at least one item.

  Related types: [BreadcrumbLink](https://docs.stripe.com/stripe-apps/components/detailpage.md#breadcrumblink). |
| `primaryColumn`   | (Required)
  `React.ReactNode`

  The primary column of the detail page. One or more `PageModule` components.                                                                                                                                                                            |
| `title`           | (Required)
  `string`

  The title of the detail page.                                                                                                                                                                                                                                   |
| `actions`         | (Optional)
  `DetailPageAction[] | undefined`

  The page actions of the detail page.

  Related types: [DetailPageAction](https://docs.stripe.com/stripe-apps/components/detailpage.md#detailpageaction).                                                                               |
| `description`     | (Optional)
  `string | undefined`

  The description of the detail page.                                                                                                                                                                                                                 |
| `pending`         | (Optional)
  `boolean | undefined`

  Whether the detail page is in a pending state. If true, a loading skeleton will be displayed instead of the content.                                                                                                                               |
| `secondaryColumn` | (Optional)
  `React.ReactNode`

  The secondary column of the detail page. One or more `PageModule` components.                                                                                                                                                                          |

### BreadcrumbLink

| Property | Type                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `label`  | (Required)
  `string`

  The label of the breadcrumb item.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `route`  | (Required)
  `{     /** Query params that are passed to Extension views via the `environment` prop. */     envParams?: {         [x: string]: string;     } | undefined;     name: "fullPageGlob";     params?: {         /** The id of the app. */         appId?: string | undefined;         /** The path segments. */         glob?: string[] | undefined;         searchParams?: SearchParams | undefined;     } | undefined; }`

  Related types: [FullPageGlobRoute](https://docs.stripe.com/stripe-apps/components/detailpage.md#fullpageglobroute). |
| `type`   | (Required)
  `"link"`

  The type of the breadcrumb item.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |

### FullPageGlobRoute

| Property    | Type                                                                                                                                                 |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`      | (Required)
  `"fullPageGlob"`                                                                                                                        |
| `envParams` | (Optional)
  `{     [x: string]: string; } | undefined`

  Query params that are passed to Extension views via the `environment` prop.               |
| `params`    | (Optional)
  `Params | undefined`

  Related types: [Params](https://docs.stripe.com/stripe-apps/components/detailpage.md#fullpageglobroute-params). |

### FullPageGlobRoute Params

| Property       | Type                                                      |
| -------------- | --------------------------------------------------------- |
| `appId`        | (Optional)
  `string | undefined`

  The id of the app.   |
| `glob`         | (Optional)
  `string[] | undefined`

  The path segments. |
| `searchParams` | (Optional)
  `SearchParams | undefined`                   |

### DetailPageAction

| Property   | Type                                                                                              |
| ---------- | ------------------------------------------------------------------------------------------------- |
| `label`    | (Required)
  `string`

  The label of the action.                                                 |
| `onPress`  | (Required)
  `() => void`

  An event handler for the action.                                     |
| `disabled` | (Optional)
  `boolean | undefined`

  Whether the action is disabled.                             |
| `type`     | (Optional)
  `("primary" | "secondary" | "destructive") | undefined`

  The type of the `Button`. |

### Breadcrumb navigation

Use the `breadcrumbs` prop to add navigational context at the top of the page. This helps users navigate back when the detail view replaces a list view.

The `title` prop represents the current page. Don’t repeat it as a trailing breadcrumb item. Breadcrumbs should contain only ancestor pages that the user can navigate back to.

Each breadcrumb item is a `link` (clickable, navigates to another page):

```jsx
import {useNavigation} from '@stripe/ui-extension-sdk/navigation';
import {DetailPage, PageModule} from '@stripe/ui-extension-sdk/ui';

export function CustomerDetail() {
  const {createAppRoute} = useNavigation();

  return (
    <DetailPage
      title="Jenny Rosen"
      breadcrumbs={[
        {
          type: 'link',
          label: 'Customers',
          route: createAppRoute('customers'),
        },
      ]}
      primaryColumn={
        <PageModule title="Overview">
          <Overview />
        </PageModule>
      }
    />
  );
}
```

The `route` property in breadcrumb links accepts a [FullPageGlobRoute](https://docs.stripe.com/stripe-apps/components/detailpage.md#fullpageglobroute) descriptor or the return value of [createAppRoute](https://docs.stripe.com/stripe-apps/routing.md) to navigate within your app.

> Don’t name a page or breadcrumb label **Home**. The Dashboard already has a Home page and using the same name creates confusion. Use **Overview** instead for your app’s top-level landing page.

### Page actions

Use the `actions` prop to display action buttons in the page header. Position your primary action first, followed by secondary and destructive actions:

```jsx
import {useNavigation} from '@stripe/ui-extension-sdk/navigation';
import {DetailPage, PageModule} from '@stripe/ui-extension-sdk/ui';

export function CustomerDetail() {
  const {createAppRoute} = useNavigation();

  return (
    <DetailPage
      title="Jenny Rosen"
      breadcrumbs={[
        {
          type: 'link',
          label: 'Customers',
          route: createAppRoute('customers'),
        },
      ]}
      actions={[
        {label: 'Send invoice', onPress: handleSendInvoice, type: 'primary'},
        {label: 'Edit details', onPress: handleEdit, type: 'secondary'},
        {label: 'Delete customer', onPress: handleDelete, type: 'destructive'},
      ]}
      primaryColumn={
        <PageModule title="Account details">
          <AccountDetails />
        </PageModule>
      }
    />
  );
}
```

### Pending state

When data is loading, set `pending={true}` to display a skeleton layout instead of content. The skeleton uses the existing `breadcrumbs` and `actions` props to render structurally accurate placeholders in the page header, so the skeleton matches the shape of the fully loaded page.

### PageModule

Use this component only within [DetailPage](https://docs.stripe.com/stripe-apps/components/detailpage.md#detailpage). It provides a consistent section with a title, optional subtitle, and optional action buttons.

Children of `PageModule` can be any UI component you need to create the desired interface.

```jsx
import {useNavigation} from '@stripe/ui-extension-sdk/navigation';
import {
  DetailPage,
  PageModule,
  List,
  ListItem,
  Inline,
} from '@stripe/ui-extension-sdk/ui';

export function CustomerDetail() {
  const {createAppRoute} = useNavigation();

  return (
    <DetailPage
      title="Jenny Rosen"
      breadcrumbs={[
        {
          type: 'link',
          label: 'Customers',
          route: createAppRoute('customers'),
        },
      ]}
      primaryColumn={
        <PageModule
          title="Payment history"
          subtitle="Last 30 days"
          extraActions={[
            {label: 'View all', onPress: () => {}, type: 'primary'},
            {label: 'Export', onPress: () => {}, type: 'secondary'},
          ]}
        >
          <List>
            <ListItem
              id="py_001"
              title={<Inline>Invoice #1042</Inline>}
              value={<Inline>$1,250.00</Inline>}
            />
            <ListItem
              id="py_002"
              title={<Inline>Invoice #1038</Inline>}
              value={<Inline>$890.00</Inline>}
            />
          </List>
        </PageModule>
      }
    />
  );
}
```

### PageModule props

| Property       | Type                                                                                                                                                                                                   |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `children`     | (Required)
  `React.ReactNode`

  The content of the module.                                                                                                                                           |
| `title`        | (Required)
  `string`

  The title of the module.                                                                                                                                                      |
| `extraActions` | (Optional)
  `PageModuleAction[] | undefined`

  The extra actions of the module.

  Related types: [PageModuleAction](https://docs.stripe.com/stripe-apps/components/detailpage.md#pagemoduleaction). |
| `subtitle`     | (Optional)
  `string | undefined`

  The subtitle of the module.                                                                                                                                       |

### PageModuleAction

| Property   | Type                                                                                              |
| ---------- | ------------------------------------------------------------------------------------------------- |
| `label`    | (Required)
  `string`

  The label of the action.                                                 |
| `onPress`  | (Required)
  `() => void`

  An event handler for the action.                                     |
| `disabled` | (Optional)
  `boolean | undefined`

  Whether the action is disabled.                             |
| `type`     | (Optional)
  `("primary" | "secondary" | "destructive") | undefined`

  The type of the `Button`. |


## See also

- [Design patterns to follow](https://docs.stripe.com/stripe-apps/patterns.md)
- [Style your app](https://docs.stripe.com/stripe-apps/style.md)
- [UI testing](https://docs.stripe.com/stripe-apps/ui-testing.md)
