---
title: Orders
description: >-
  Order pages display customer purchases, including line items, payment status,
  fulfillment details, and shipping information. Extensions help merchants
  streamline fulfillment workflows, integrate with external logistics systems,
  and provide real-time order insights.
api_version: 2026-04-rc
source_url:
  html: 'https://shopify.dev/docs/api/admin-extensions/2026-04-rc/targets/orders'
  md: 'https://shopify.dev/docs/api/admin-extensions/2026-04-rc/targets/orders.md'
---

# Orders

Order pages display customer purchases, including line items, payment status, fulfillment details, and shipping information. Extensions help merchants streamline fulfillment workflows, integrate with external logistics systems, and provide real-time order insights. Learn more about [managing orders](https://help.shopify.com/manual/orders) in the Shopify admin.

### Use cases

* **Fulfillment and shipping integration:** Connect orders with external fulfillment providers, 3PLs, or shipping carriers to automate label generation, track shipments, and sync fulfillment status across systems.
* **Customer communication workflows:** Send order confirmations, shipping updates, or custom notifications through external communication platforms like email services, SMS gateways, or messaging apps.
* **Fraud detection and risk assessment:** Flag potentially fraudulent orders, display risk scores from external fraud prevention services, or trigger manual review workflows for suspicious transactions.
* **Order analytics and reporting:** Display order insights, export data to business intelligence tools, or generate custom reports for sales analysis, inventory planning, or financial reconciliation.
* **Bulk order operations:** Process multiple orders at once for batch fulfillment, mass invoice generation, bulk status updates, or exporting order data to accounting and ERP systems.

![Shopify admin order pages showing all available extension target locations.](https://shopify.dev/assets/assets/images/templated-apis-screenshots/admin-extensions/targets-overview-images/admin.order.overview-DOS2HSJU.png)

***

## Order details targets

Use [action and block targets](https://shopify.dev/docs/api/admin-extensions/2026-04-rc#building-your-extension) to extend the order details page with workflows and contextual information.

Action targets open as modal overlays from the **More actions** menu, while block targets display as inline cards. The examples demonstrate fetching data from the [direct API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc#direct-api-access) or your [app's backend](https://shopify.dev/docs/api/admin-extensions/2026-04-rc#app-authentication).

### Order details action target

`admin.order-details.action.render`

Renders an admin action extension on the order details page. Merchants can access this extension from the **More actions** menu. Use this target to provide workflows that operate on order data, such as syncing with external systems, exporting order information, or managing credit terms.

Extensions at this target can access order data through the `data` property in the [Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/action-extension-api). The action renders in a modal overlay, providing space for multi-step workflows, forms, and confirmations.

### Support Components (45) APIs (1)

### Supported components

* [Admin action](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/settings-and-templates/admin-action)
* [Avatar](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/avatar)
* [Badge](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/badge)
* [Banner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/banner)
* [Box](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/box)
* [Button](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button)
* [Button group](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button-group)
* [Checkbox](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/checkbox)
* [Chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/chip)
* [Choice list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/choice-list)
* [Clickable](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable)
* [Clickable chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable-chip)
* [Color field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-field)
* [Color picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-picker)
* [Date field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-field)
* [Date picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-picker)
* [Divider](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/divider)
* [Drop zone](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/drop-zone)
* [Email field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/email-field)
* [Grid](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/grid)
* [Heading](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/heading)
* [Icon](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/icon)
* [Image](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/image)
* [Link](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/link)
* [Menu](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/menu)
* [Money field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/money-field)
* [Number field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/number-field)
* [Ordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/ordered-list)
* [Paragraph](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/paragraph)
* [Password field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/password-field)
* [Query container](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/query-container)
* [Search field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/search-field)
* [Section](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/section)
* [Select](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/select)
* [Spinner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/spinner)
* [Stack](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/stack)
* [Switch](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/switch)
* [Table](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/table)
* [Text](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/text)
* [Text area](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-area)
* [Text field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-field)
* [Thumbnail](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/thumbnail)
* [Tooltip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/tooltip)
* [Url field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/url-field)
* [Unordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/unordered-list)

### Available APIs

* [Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/action-extension-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that pushes order data to your ERP system. This example demonstrates calling your app backend with order details and handling the sync response.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeLineItems, setIncludeLineItems] = useState(true);
    const [includeCustomer, setIncludeCustomer] = useState(true);
    const [priority, setPriority] = useState('normal');

    const handleExport = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('https://your-app.com/api/erp/export-order', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderId,
            includeLineItems,
            includeCustomer,
            priority,
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const data = await response.json();
          setError(data.message || 'Failed to export order to ERP');
        }
      } catch (err) {
        setError('Connection error. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Order successfully exported to ERP system!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include line items"
              checked={includeLineItems}
              onChange={(e) => setIncludeLineItems(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include customer data"
              checked={includeCustomer}
              onChange={(e) => setIncludeCustomer(e.currentTarget.checked)}
            />
            <s-select
              label="Processing priority"
              value={priority}
              onChange={(e) => setPriority(e.currentTarget.value)}
            >
              <s-option value="low">Low</s-option>
              <s-option value="normal">Normal</s-option>
              <s-option value="high">High (Rush)</s-option>
            </s-select>
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success}
        >
          {loading ? 'Exporting...' : 'Export to ERP'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates a custom packing slip PDF for an order. This example demonstrates fetching order details using \[direct API]\(/docs/api/admin-extensions/2026-04-rc#direct-api-access) GraphQL endpoint and creating a downloadable document.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includePrices, setIncludePrices] = useState(false);

    const handleGenerate = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('shopify:admin/api/graphql.json', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            query: `query GetOrder($id: ID!) {
              order(id: $id) {
                name
                createdAt
                shippingAddress {
                  name
                  address1
                  city
                  provinceCode
                  zip
                  country
                }
                lineItems(first: 50) {
                  nodes {
                    title
                    quantity
                    sku
                  }
                }
              }
            }`,
            variables: {id: orderId},
          }),
        });

        const {data, errors} = await response.json();

        if (errors) {
          throw new Error(errors[0].message);
        }

        console.log('Packing slip data:', data.order, {includeBarcode, includePrices});
        setSuccess(true);
        shopify.close();
      } catch (err) {
        setError(err.message || 'Failed to generate packing slip');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Generate Packing Slip">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Packing slip generated! Download starting...
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>{error}</s-banner>
        )}

        <s-section heading="Packing Slip Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include barcode"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include item prices"
              checked={includePrices}
              onChange={(e) => setIncludePrices(e.currentTarget.checked)}
            />
            <s-text color="subdued">
              The packing slip will include shipping address and line items.
            </s-text>
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleGenerate}
          disabled={loading || success}
        >
          {loading ? 'Generating...' : 'Generate PDF'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

### Order details action (should render) target

`admin.order-details.action.should-render`

Controls the render state of an admin action extension on the order details page. Use this target to conditionally show or hide your action extension based on the order's properties, such as status, configuration, or specific business requirements.

This target returns a boolean value that determines whether the corresponding action extension appears in the **More actions** menu. The extension evaluates each time the page loads.

### Support Components (0) APIs (1)

### Supported components

\-

### Available APIs

* [Should Render API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/utility-apis/should-render-api)

Examples

### Examples

* ####

  ##### Description

  Show the action only when the app backend confirms real-time fulfillment tracking is available for this order's carrier and destination.

  ##### jsx

  ```jsx
  export default async () => {
    const orderId = shopify.data.selected[0].id;

    try {
      const response = await fetch('https://your-app.com/api/fulfillment/check-tracking', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          orderId,
          checkType: 'realtime-tracking',
        }),
      });

      if (!response.ok) {
        console.error('Tracking API returned error:', response.status);
        return { display: false };
      }

      const result = await response.json();
      
      // Show action if carrier supports real-time tracking
      // and order has at least one unfulfilled item
      return {
        display: result.carrierSupportsTracking && result.hasUnfulfilledItems,
      };
    } catch (err) {
      console.error('Failed to check fulfillment tracking:', err);
      return { display: false };
    }
  };
  ```

* ####

  ##### Description

  Show the fraud risk assessment action only for orders that have a risk level of HIGH or MEDIUM, allowing merchants to quickly review potentially fraudulent orders.

  ##### jsx

  ```jsx
  export default async () => {
    const orderId = shopify.data.selected[0].id;

    try {
      const response = await fetch('shopify:admin/api/graphql.json', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          query: `query GetOrderRisk($id: ID!) {
            order(id: $id) {
              risk {
                assessments {
                  riskLevel
                }
              }
            }
          }`,
          variables: {id: orderId},
        }),
      });

      const {data} = await response.json();
      const assessments = data?.order?.risk?.assessments || [];
      
      const hasElevatedRisk = assessments.some(
        (assessment) => assessment.riskLevel === 'HIGH' || assessment.riskLevel === 'MEDIUM'
      );

      return {display: hasElevatedRisk};
    } catch (err) {
      console.error('Error checking order risk:', err);
      return {display: false};
    }
  };
  ```

### Order details block target

`admin.order-details.block.render`

Renders an admin block extension inline on the order details page. Use this target to display contextual information, analytics, or status updates related to the order without requiring merchant interaction to open a modal.

Extensions at this target can access order data through the `data` property in the [Block Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/block-extension-api). Blocks appear as cards on the page and can show real-time data, insights, or quick actions. They provide persistent visibility for information merchants need to see at a glance.

### Support Components (46) APIs (1)

### Supported components

* [Admin block](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/settings-and-templates/admin-block)
* [Avatar](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/avatar)
* [Badge](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/badge)
* [Banner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/banner)
* [Box](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/box)
* [Button](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button)
* [Button group](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button-group)
* [Checkbox](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/checkbox)
* [Chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/chip)
* [Choice list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/choice-list)
* [Clickable](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable)
* [Clickable chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable-chip)
* [Color field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-field)
* [Color picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-picker)
* [Date field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-field)
* [Date picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-picker)
* [Divider](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/divider)
* [Drop zone](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/drop-zone)
* [Email field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/email-field)
* [Form](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/form)
* [Grid](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/grid)
* [Heading](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/heading)
* [Icon](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/icon)
* [Image](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/image)
* [Link](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/link)
* [Menu](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/menu)
* [Money field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/money-field)
* [Number field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/number-field)
* [Ordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/ordered-list)
* [Paragraph](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/paragraph)
* [Password field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/password-field)
* [Query container](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/query-container)
* [Search field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/search-field)
* [Section](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/section)
* [Select](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/select)
* [Spinner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/spinner)
* [Stack](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/stack)
* [Switch](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/switch)
* [Table](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/table)
* [Text](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/text)
* [Text area](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-area)
* [Text field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-field)
* [Thumbnail](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/thumbnail)
* [Tooltip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/tooltip)
* [Url field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/url-field)
* [Unordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/unordered-list)

### Available APIs

* [Block Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/block-extension-api)

Examples

### Examples

* ####

  ##### Description

  Create a block extension that displays real-time fulfillment progress by fetching tracking data from your app backend and showing shipment status with carrier information.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState, useEffect} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);
    const [fulfillment, setFulfillment] = useState(null);

    useEffect(() => {
      fetchFulfillmentStatus();
    }, []);

    const fetchFulfillmentStatus = async () => {
      setLoading(true);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('https://your-app.com/api/fulfillment/status', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({orderId}),
        });

        if (response.ok) {
          const data = await response.json();
          setFulfillment(data);
        } else {
          setError(true);
        }
      } catch (err) {
        setError(true);
      } finally {
        setLoading(false);
      }
    };

    const getStatusBadge = (status) => {
      const tones = {
        pending: 'warning',
        in_transit: 'info',
        delivered: 'success',
        failed: 'critical',
      };
      return <s-badge tone={tones[status] || 'info'}>{status.replace('_', ' ')}</s-badge>;
    };

    if (loading) {
      return (
        <s-admin-block heading="Fulfillment Status">
          <s-box padding="base">
            <s-spinner size="base" />
          </s-box>
        </s-admin-block>
      );
    }

    if (error) {
      return (
        <s-admin-block heading="Fulfillment Status">
          <s-banner tone="critical" dismissible={false}>
            Unable to fetch fulfillment status.
          </s-banner>
        </s-admin-block>
      );
    }

    return (
      <s-admin-block heading="Fulfillment Status">
        <s-stack gap="base">
          <s-box>
            <s-stack gap="small">
              <s-text type="strong">Status</s-text>
              {getStatusBadge(fulfillment?.status || 'pending')}
            </s-stack>
          </s-box>

          <s-divider />

          <s-box>
            <s-stack gap="small">
              <s-text type="strong">Carrier</s-text>
              <s-text>{fulfillment?.carrier || 'Not assigned'}</s-text>
            </s-stack>
          </s-box>

          <s-box>
            <s-stack gap="small">
              <s-text type="strong">Tracking Number</s-text>
              {fulfillment?.trackingNumber ? (
                <s-link href={fulfillment.trackingUrl}>{fulfillment.trackingNumber}</s-link>
              ) : (
                <s-text color="subdued">Not available</s-text>
              )}
            </s-stack>
          </s-box>

          <s-box>
            <s-stack gap="small">
              <s-text type="strong">Estimated Delivery</s-text>
              <s-text>{fulfillment?.estimatedDelivery || 'Unknown'}</s-text>
            </s-stack>
          </s-box>

          <s-button onClick={fetchFulfillmentStatus}>Refresh Status</s-button>
        </s-stack>
      </s-admin-block>
    );
  };
  ```

* ####

  ##### Description

  Create a block extension that displays fraud risk assessment for an order by fetching order data using the \[GraphQL Admin API]\(/docs/api/admin-graphql) and calculating risk indicators based on order attributes.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState, useEffect} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(true);
    const [riskData, setRiskData] = useState(null);
    const [error, setError] = useState(false);

    useEffect(() => {
      fetchRiskData();
    }, []);

    const fetchRiskData = async () => {
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('shopify:admin/api/graphql.json', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            query: `query GetOrderRisk($id: ID!) {
              order(id: $id) {
                name
                totalPriceSet { shopMoney { amount currencyCode } }
                billingAddressMatchesShippingAddress
                customer { numberOfOrders }
                riskLevel
              }
            }`,
            variables: {id: orderId},
          }),
        });

        const {data} = await response.json();
        const order = data.order;
        
        setRiskData({
          orderName: order.name,
          amount: parseFloat(order.totalPriceSet.shopMoney.amount),
          currency: order.totalPriceSet.shopMoney.currencyCode,
          addressMatch: order.billingAddressMatchesShippingAddress,
          customerOrders: order.customer?.numberOfOrders || 0,
          riskLevel: order.riskLevel,
        });
      } catch (err) {
        setError(true);
      } finally {
        setLoading(false);
      }
    };

    const getRiskBadge = (level) => {
      const tones = {LOW: 'success', MEDIUM: 'warning', HIGH: 'critical'};
      return <s-badge tone={tones[level] || 'warning'}>{level}</s-badge>;
    };

    if (loading) {
      return (
        <s-admin-block heading="Risk Assessment">
          <s-box padding="base"><s-spinner size="base" /></s-box>
        </s-admin-block>
      );
    }

    if (error) {
      return (
        <s-admin-block heading="Risk Assessment">
          <s-banner tone="critical" dismissible={false}>Failed to load risk data</s-banner>
        </s-admin-block>
      );
    }

    return (
      <s-admin-block heading="Risk Assessment">
        <s-stack gap="base">
          <s-box>
            <s-text type="strong">Overall Risk: </s-text>
            {getRiskBadge(riskData.riskLevel)}
          </s-box>
          <s-divider />
          <s-section heading="Risk Indicators">
            <s-stack gap="small">
              <s-box>
                <s-text>Order Value: </s-text>
                <s-badge tone={riskData.amount > 500 ? 'warning' : 'success'}>
                  {riskData.currency} {riskData.amount.toFixed(2)}
                </s-badge>
              </s-box>
              <s-box>
                <s-text>Address Match: </s-text>
                <s-badge tone={riskData.addressMatch ? 'success' : 'warning'}>
                  {riskData.addressMatch ? 'Yes' : 'No'}
                </s-badge>
              </s-box>
              <s-box>
                <s-text>Customer History: </s-text>
                <s-badge tone={riskData.customerOrders > 0 ? 'success' : 'warning'}>
                  {riskData.customerOrders} prior orders
                </s-badge>
              </s-box>
            </s-stack>
          </s-section>
        </s-stack>
      </s-admin-block>
    );
  };
  ```

### Order details print action target

`admin.order-details.print-action.render`

Renders an admin print action extension on the order details page. Merchants access this extension from the **Print** menu in the toolbar. Use this target to provide custom print workflows such as generating packing slips, shipping labels, invoices, or other order-related documents. The extension contains special APIs to display a preview of the document and send it to a printer.

### Support Components (45) APIs (1)

### Supported components

* [Admin print action](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/settings-and-templates/admin-print-action)
* [Avatar](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/avatar)
* [Badge](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/badge)
* [Banner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/banner)
* [Box](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/box)
* [Button](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button)
* [Button group](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button-group)
* [Checkbox](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/checkbox)
* [Chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/chip)
* [Choice list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/choice-list)
* [Clickable](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable)
* [Clickable chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable-chip)
* [Color field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-field)
* [Color picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-picker)
* [Date field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-field)
* [Date picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-picker)
* [Divider](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/divider)
* [Drop zone](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/drop-zone)
* [Email field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/email-field)
* [Grid](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/grid)
* [Heading](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/heading)
* [Icon](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/icon)
* [Image](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/image)
* [Link](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/link)
* [Menu](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/menu)
* [Money field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/money-field)
* [Number field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/number-field)
* [Ordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/ordered-list)
* [Paragraph](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/paragraph)
* [Password field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/password-field)
* [Query container](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/query-container)
* [Search field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/search-field)
* [Section](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/section)
* [Select](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/select)
* [Spinner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/spinner)
* [Stack](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/stack)
* [Switch](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/switch)
* [Table](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/table)
* [Text](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/text)
* [Text area](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-area)
* [Text field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-field)
* [Thumbnail](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/thumbnail)
* [Tooltip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/tooltip)
* [Url field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/url-field)
* [Unordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/unordered-list)

### Available APIs

* [Print Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/print-action-extension-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that pushes order data to your ERP system for inventory and accounting sync. This example demonstrates calling an app backend API with order details and handling the response.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeNotes, setIncludeNotes] = useState(true);
    const [priority, setPriority] = useState('normal');

    const handleExport = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('https://your-app.com/api/erp/export-order', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderId,
            includeNotes,
            priority,
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const data = await response.json();
          setError(data.message || 'Failed to export order to ERP');
        }
      } catch (err) {
        setError('Connection error. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Order successfully exported to ERP system!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Options">
          <s-stack gap="base">
            <s-text color="subdued">
              This will sync the order with your ERP for processing.
            </s-text>
            <s-checkbox
              label="Include order notes"
              checked={includeNotes}
              onChange={(e) => setIncludeNotes(e.currentTarget.checked)}
            />
            <s-select
              label="Processing priority"
              value={priority}
              onChange={(e) => setPriority(e.currentTarget.value)}
            >
              <s-option value="low">Low</s-option>
              <s-option value="normal">Normal</s-option>
              <s-option value="high">High - Rush Order</s-option>
            </s-select>
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success}
        >
          {loading ? 'Exporting...' : 'Export to ERP'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates a custom packing slip for an order. This example demonstrates fetching order details using the GraphQL Admin API and creating a printable packing slip document.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState, useEffect} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(true);
    const [generating, setGenerating] = useState(false);
    const [order, setOrder] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includeNotes, setIncludeNotes] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);

    useEffect(() => {
      fetchOrderDetails();
    }, []);

    const fetchOrderDetails = async () => {
      const orderId = shopify.data.selected[0].id;
      const response = await fetch('shopify:admin/api/graphql.json', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          query: `query GetOrder($id: ID!) {
            order(id: $id) {
              name
              createdAt
              shippingAddress { formatted }
              lineItems(first: 50) {
                nodes { title quantity sku }
              }
              note
            }
          }`,
          variables: {id: orderId},
        }),
      });
      const {data} = await response.json();
      setOrder(data.order);
      setLoading(false);
    };

    const handleGenerate = async () => {
      setGenerating(true);
      try {
        // Simulate packing slip generation
        await new Promise(resolve => setTimeout(resolve, 1500));
        setSuccess(true);
        shopify.close();
      } catch (err) {
        setError('Failed to generate packing slip');
      } finally {
        setGenerating(false);
      }
    };

    if (loading) {
      return (
        <s-admin-action heading="Generate Packing Slip">
          <s-box padding="large"><s-spinner size="base" /></s-box>
        </s-admin-action>
      );
    }

    return (
      <s-admin-action heading="Generate Packing Slip">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Packing slip generated! Opening print dialog...
          </s-banner>
        )}
        {error && <s-banner tone="critical" dismissible={false}>{error}</s-banner>}

        <s-section heading="Order Details">
          <s-stack gap="small">
            <s-text type="strong">{order.name}</s-text>
            <s-text color="subdued">{order.lineItems.nodes.length} items</s-text>
          </s-stack>
        </s-section>

        <s-section heading="Packing Slip Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include barcode"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include order notes"
              checked={includeNotes}
              onChange={(e) => setIncludeNotes(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleGenerate}
          disabled={generating || success}
        >
          {generating ? 'Generating...' : 'Generate & Print'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

### Order details print action (should render) target

`admin.order-details.print-action.should-render`

Controls the render state of an admin action extension on the order details page. Use this target to conditionally show or hide your action extension based on the order's properties, such as status, configuration, or specific business requirements.

This target returns a boolean value that determines whether the corresponding action extension appears in the **More actions** menu. The extension evaluates each time the page loads.

### Support Components (0) APIs (1)

### Supported components

\-

### Available APIs

* [Should Render API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/utility-apis/should-render-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that pushes order data to your ERP system using your app backend. This example demonstrates calling an external API endpoint with order details and handling the sync response.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeNotes, setIncludeNotes] = useState(true);
    const [priority, setPriority] = useState('normal');

    const handleExport = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('https://your-app.com/api/erp/export-order', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderId,
            includeNotes,
            priority,
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const data = await response.json();
          setError(data.message || 'Failed to export order to ERP');
        }
      } catch (err) {
        setError('Connection error. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Order successfully exported to ERP system!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include order notes"
              checked={includeNotes}
              onChange={(e) => setIncludeNotes(e.currentTarget.checked)}
            />
            <s-select
              label="Processing priority"
              value={priority}
              onChange={(e) => setPriority(e.currentTarget.value)}
            >
              <s-option value="low">Low</s-option>
              <s-option value="normal">Normal</s-option>
              <s-option value="high">High - Rush Order</s-option>
            </s-select>
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success}
        >
          {loading ? 'Exporting...' : 'Export to ERP'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates a custom packing slip PDF for an order. This example demonstrates fetching order details using GraphQL Admin API and creating a downloadable packing slip document.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includeNotes, setIncludeNotes] = useState(false);
    const [copies, setCopies] = useState('1');

    const handleGenerate = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('shopify:admin/api/graphql.json', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            query: `query GetOrderForPackingSlip($id: ID!) {
              order(id: $id) {
                name
                createdAt
                shippingAddress { formatted }
                lineItems(first: 50) {
                  nodes { title quantity sku }
                }
                note
              }
            }`,
            variables: {id: orderId},
          }),
        });

        const {data} = await response.json();

        if (data?.order) {
          setSuccess(true);
          shopify.close();
        } else {
          setError('Could not fetch order details');
        }
      } catch (err) {
        setError('Failed to generate packing slip');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Generate Packing Slip">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Packing slip generated! Opening print dialog...
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>{error}</s-banner>
        )}

        <s-section heading="Packing Slip Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include barcode"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include order notes"
              checked={includeNotes}
              onChange={(e) => setIncludeNotes(e.currentTarget.checked)}
            />
            <s-select
              label="Number of copies"
              value={copies}
              onChange={(e) => setCopies(e.currentTarget.value)}
            >
              <s-option value="1">1 copy</s-option>
              <s-option value="2">2 copies</s-option>
              <s-option value="3">3 copies</s-option>
            </s-select>
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleGenerate}
          disabled={loading || success}
        >
          {loading ? 'Generating...' : 'Generate & Print'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

***

## Order index targets

Use [action targets](https://shopify.dev/docs/api/admin-extensions/2026-04-rc#building-your-extension) to extend the order index page with workflows and operations.

### Order index action target

`admin.order-index.action.render`

Renders an admin action extension on the orders index page. Merchants can access this extension from the **More actions** menu. Use this target to provide workflows that operate on order data, such as syncing with external systems, exporting order information, or managing credit terms.

Extensions at this target can access order data through the `data` property in the [Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/action-extension-api). The action renders in a modal overlay, providing space for multi-step workflows, forms, and confirmations.

### Support Components (45) APIs (1)

### Supported components

* [Admin action](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/settings-and-templates/admin-action)
* [Avatar](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/avatar)
* [Badge](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/badge)
* [Banner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/banner)
* [Box](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/box)
* [Button](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button)
* [Button group](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button-group)
* [Checkbox](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/checkbox)
* [Chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/chip)
* [Choice list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/choice-list)
* [Clickable](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable)
* [Clickable chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable-chip)
* [Color field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-field)
* [Color picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-picker)
* [Date field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-field)
* [Date picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-picker)
* [Divider](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/divider)
* [Drop zone](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/drop-zone)
* [Email field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/email-field)
* [Grid](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/grid)
* [Heading](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/heading)
* [Icon](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/icon)
* [Image](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/image)
* [Link](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/link)
* [Menu](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/menu)
* [Money field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/money-field)
* [Number field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/number-field)
* [Ordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/ordered-list)
* [Paragraph](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/paragraph)
* [Password field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/password-field)
* [Query container](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/query-container)
* [Search field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/search-field)
* [Section](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/section)
* [Select](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/select)
* [Spinner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/spinner)
* [Stack](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/stack)
* [Switch](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/switch)
* [Table](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/table)
* [Text](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/text)
* [Text area](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-area)
* [Text field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-field)
* [Thumbnail](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/thumbnail)
* [Tooltip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/tooltip)
* [Url field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/url-field)
* [Unordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/unordered-list)

### Available APIs

* [Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/action-extension-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that pushes selected orders to your ERP system. This example demonstrates calling your app backend with selected order IDs and handling the sync response.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeLineItems, setIncludeLineItems] = useState(true);
    const [includeCustomer, setIncludeCustomer] = useState(true);

    const selectedOrders = shopify.data.selected;
    const orderCount = selectedOrders.length;

    const handleExport = async () => {
      setLoading(true);
      setError(null);

      try {
        const response = await fetch('https://your-app.com/api/erp/export-orders', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderIds: selectedOrders.map(order => order.id),
            options: {
              includeLineItems,
              includeCustomer,
            },
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const data = await response.json();
          setError(data.message || 'Failed to export orders');
        }
      } catch (err) {
        setError('Connection failed. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Successfully exported {orderCount} order(s) to ERP!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Options">
          <s-stack gap="base">
            <s-text color="subdued">
              {orderCount} order(s) selected for export
            </s-text>
            <s-checkbox
              label="Include line items"
              checked={includeLineItems}
              onChange={(e) => setIncludeLineItems(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include customer details"
              checked={includeCustomer}
              onChange={(e) => setIncludeCustomer(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success || orderCount === 0}
        >
          {loading ? 'Exporting...' : `Export ${orderCount} Order(s)`}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates a custom packing slip PDF for selected orders. This example demonstrates using the \[direct API]\(/docs/api/admin-extensions/2026-04-rc#direct-api-access) using fetch to query order details including line items and shipping address.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includePrices, setIncludePrices] = useState(false);

    const handleGenerate = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('shopify:admin/api/graphql.json', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            query: `query GetOrder($id: ID!) {
              order(id: $id) {
                name
                createdAt
                shippingAddress {
                  name
                  address1
                  city
                  provinceCode
                  zip
                  country
                }
                lineItems(first: 50) {
                  nodes {
                    title
                    quantity
                    sku
                  }
                }
              }
            }`,
            variables: {id: orderId},
          }),
        });

        const {data} = await response.json();
        
        if (data?.order) {
          const itemCount = data.order.lineItems.nodes.length;
          setSuccess(true);
          shopify.close();
        } else {
          setError('Order not found');
        }
      } catch (err) {
        setError('Failed to generate packing slip');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Generate Packing Slip">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Packing slip generated and ready for download!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>{error}</s-banner>
        )}

        <s-section heading="Packing Slip Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include barcode for scanning"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Show item prices"
              checked={includePrices}
              onChange={(e) => setIncludePrices(e.currentTarget.checked)}
            />
            <s-text color="subdued">
              PDF will include shipping address and line items
            </s-text>
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleGenerate}
          disabled={loading || success}
        >
          {loading ? 'Generating...' : 'Generate PDF'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

### Order index action (should render) target

`admin.order-index.action.should-render`

Controls the render state of an admin action extension on the orders index page. Use this target to conditionally show or hide your action extension based on the order's properties, such as status, configuration, or specific business requirements.

This target returns a boolean value that determines whether the corresponding action extension appears in the **More actions** menu. The extension evaluates each time the page loads.

### Support Components (0) APIs (1)

### Supported components

\-

### Available APIs

* [Should Render API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/utility-apis/should-render-api)

Examples

### Examples

* ####

  ##### Description

  Show the action only when your app backend confirms real-time fulfillment tracking is available for the selected orders.

  ##### jsx

  ```jsx
  export default async () => {
    const selectedOrders = shopify.data.selected;
    
    if (!selectedOrders || selectedOrders.length === 0) {
      return { display: false };
    }

    try {
      const orderIds = selectedOrders.map(order => order.id);
      
      const response = await fetch('https://your-app.com/api/fulfillment/check-tracking', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          orderIds,
          checkType: 'realtime-tracking',
        }),
      });

      if (!response.ok) {
        return { display: false };
      }

      const result = await response.json();
      
      // Show action if tracking is available for at least one order
      return { display: result.trackingAvailable === true };
    } catch (err) {
      console.error('Fulfillment tracking check failed:', err);
      return { display: false };
    }
  };
  ```

* ####

  ##### Description

  Show the fraud risk assessment action only for orders that have a risk level of HIGH or MEDIUM, allowing merchants to quickly review potentially fraudulent orders.

  ##### jsx

  ```jsx
  export default async () => {
    const orderId = shopify.data.selected[0].id;

    try {
      const response = await fetch('shopify:admin/api/graphql.json', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          query: `query GetOrderRisk($id: ID!) {
            order(id: $id) {
              risk {
                assessments {
                  riskLevel
                }
              }
            }
          }`,
          variables: { id: orderId },
        }),
      });

      const { data } = await response.json();
      const assessments = data?.order?.risk?.assessments || [];
      
      const hasElevatedRisk = assessments.some(
        (assessment) => assessment.riskLevel === 'HIGH' || assessment.riskLevel === 'MEDIUM'
      );

      return { display: hasElevatedRisk };
    } catch (err) {
      console.error('Error checking order risk:', err);
      return { display: false };
    }
  };
  ```

### Order index selection action target

`admin.order-index.selection-action.render`

Renders a selection action extension on the order index page when one or more orders are selected. Merchants can access this extension from the bulk actions menu when selecting orders. Use this target to provide batch operations like bulk fulfillment, mass exports, or multi-order processing workflows.

Extensions at this target receive a list of selected order IDs through the `data.selected` property, enabling bulk processing of multiple orders in a single action.

### Support Components (45) APIs (1)

### Supported components

* [Admin action](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/settings-and-templates/admin-action)
* [Avatar](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/avatar)
* [Badge](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/badge)
* [Banner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/banner)
* [Box](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/box)
* [Button](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button)
* [Button group](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button-group)
* [Checkbox](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/checkbox)
* [Chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/chip)
* [Choice list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/choice-list)
* [Clickable](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable)
* [Clickable chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable-chip)
* [Color field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-field)
* [Color picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-picker)
* [Date field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-field)
* [Date picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-picker)
* [Divider](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/divider)
* [Drop zone](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/drop-zone)
* [Email field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/email-field)
* [Grid](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/grid)
* [Heading](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/heading)
* [Icon](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/icon)
* [Image](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/image)
* [Link](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/link)
* [Menu](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/menu)
* [Money field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/money-field)
* [Number field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/number-field)
* [Ordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/ordered-list)
* [Paragraph](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/paragraph)
* [Password field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/password-field)
* [Query container](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/query-container)
* [Search field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/search-field)
* [Section](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/section)
* [Select](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/select)
* [Spinner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/spinner)
* [Stack](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/stack)
* [Switch](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/switch)
* [Table](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/table)
* [Text](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/text)
* [Text area](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-area)
* [Text field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-field)
* [Thumbnail](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/thumbnail)
* [Tooltip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/tooltip)
* [Url field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/url-field)
* [Unordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/unordered-list)

### Available APIs

* [Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/action-extension-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that pushes selected orders to your ERP system. This example demonstrates how to send multiple order IDs to an app backend API and handle batch processing with progress feedback.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeLineItems, setIncludeLineItems] = useState(true);
    const [includeCustomer, setIncludeCustomer] = useState(true);

    const selectedOrders = shopify.data.selected;
    const orderCount = selectedOrders.length;

    const handleExport = async () => {
      setLoading(true);
      setError(null);

      try {
        const orderIds = selectedOrders.map(order => order.id);
        
        const response = await fetch('https://your-app.com/api/erp/export-orders', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderIds,
            includeLineItems,
            includeCustomer,
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const data = await response.json();
          setError(data.message || 'Failed to export orders');
        }
      } catch (err) {
        setError('Connection failed. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Successfully exported {orderCount} order(s) to ERP system!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Options">
          <s-stack gap="base">
            <s-text color="subdued">
              {orderCount} order(s) selected for export
            </s-text>
            <s-checkbox
              label="Include line items"
              checked={includeLineItems}
              onChange={(e) => setIncludeLineItems(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include customer details"
              checked={includeCustomer}
              onChange={(e) => setIncludeCustomer(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success}
        >
          {loading ? 'Exporting...' : `Export ${orderCount} Order(s)`}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates custom packing slip PDFs for selected orders. This example demonstrates using the GraphQL Admin API using fetch to retrieve order details including line items and shipping address for packing slip generation.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includePrices, setIncludePrices] = useState(false);

    const selectedCount = shopify.data.selected.length;

    const handleGenerate = async () => {
      setLoading(true);
      setError(null);

      try {
        const query = `
          query GetOrderDetails($ids: [ID!]!) {
            nodes(ids: $ids) {
              ... on Order {
                id
                name
                shippingAddress { address1 city provinceCode postalCode country }
                lineItems(first: 50) {
                  nodes { title quantity sku }
                }
              }
            }
          }
        `;

        const response = await fetch('shopify:admin/api/graphql.json', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            query,
            variables: { ids: shopify.data.selected.map(s => s.id) }
          }),
        });

        const {data, errors} = await response.json();

        if (errors) {
          throw new Error(errors[0].message);
        }

        // In production, send data to your backend to generate PDF
        console.log('Generating packing slips for:', data.nodes);
        
        setSuccess(true);
        shopify.close();
      } catch (err) {
        setError(err.message || 'Failed to generate packing slips');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Generate Packing Slips">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Generated {selectedCount} packing slip(s)! Download starting...
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>{error}</s-banner>
        )}

        <s-section heading="Packing Slip Options">
          <s-stack gap="base">
            <s-text color="subdued">
              Generating packing slips for {selectedCount} order(s)
            </s-text>
            <s-checkbox
              label="Include barcode for scanning"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include item prices"
              checked={includePrices}
              onChange={(e) => setIncludePrices(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleGenerate}
          disabled={loading || success}
        >
          {loading ? 'Generating...' : `Generate ${selectedCount} Slip(s)`}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

### Order index selection action (should render) target

`admin.order-index.selection-action.should-render`

Controls the render state of a selection action extension on the orders index page. Use this target to conditionally show or hide your action extension based on the order's properties, such as status, configuration, or specific business requirements.

This target returns a boolean value that determines whether the corresponding action extension appears in the **More actions** menu. The extension evaluates each time the page loads.

### Support Components (0) APIs (1)

### Supported components

\-

### Available APIs

* [Should Render API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/utility-apis/should-render-api)

Examples

### Examples

* ####

  ##### Description

  Show the action only when selected orders have pending fulfillment tasks tracked in your app's fulfillment management system.

  ##### jsx

  ```jsx
  export default async () => {
    const selectedIds = shopify.data.selected.map(item => item.id);

    try {
      const response = await fetch('https://your-app.com/api/fulfillment/check-status', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          orderIds: selectedIds,
        }),
      });

      if (!response.ok) {
        console.error('Failed to check fulfillment status');
        return { display: false };
      }

      const result = await response.json();

      // Show action if any selected orders have pending fulfillment tasks
      return { display: result.hasPendingFulfillment };
    } catch (err) {
      console.error('Error checking fulfillment status:', err);
      return { display: false };
    }
  };
  ```

* ####

  ##### Description

  Show the fraud assessment action only for orders that have a high or medium risk level, using the GraphQL Admin API to check the order's risk assessment data.

  ##### jsx

  ```jsx
  export default async () => {
    const orderId = shopify.data.selected[0].id;

    try {
      const response = await fetch('shopify:admin/api/graphql.json', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          query: `query GetOrderRisk($id: ID!) {
            order(id: $id) {
              risk {
                assessments {
                  riskLevel
                }
              }
            }
          }`,
          variables: {id: orderId},
        }),
      });

      const {data} = await response.json();
      const assessments = data?.order?.risk?.assessments || [];
      
      // Show action if any assessment indicates high or medium risk
      const hasElevatedRisk = assessments.some(
        (assessment) => assessment.riskLevel === 'HIGH' || assessment.riskLevel === 'MEDIUM'
      );

      return {display: hasElevatedRisk};
    } catch (err) {
      console.error('Error checking order risk:', err);
      return {display: false};
    }
  };
  ```

### Order index selection print action target

`admin.order-index.selection-print-action.render`

Renders an admin print action extension on the order index page when multiple orders are selected. Merchants access this extension from the **Print** menu in the bulk actions toolbar. Use this target to provide bulk print workflows such as generating packing slips, shipping labels, or invoices for multiple orders at once.

### Support Components (45) APIs (1)

### Supported components

* [Admin print action](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/settings-and-templates/admin-print-action)
* [Avatar](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/avatar)
* [Badge](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/badge)
* [Banner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/banner)
* [Box](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/box)
* [Button](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button)
* [Button group](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button-group)
* [Checkbox](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/checkbox)
* [Chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/chip)
* [Choice list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/choice-list)
* [Clickable](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable)
* [Clickable chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable-chip)
* [Color field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-field)
* [Color picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-picker)
* [Date field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-field)
* [Date picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-picker)
* [Divider](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/divider)
* [Drop zone](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/drop-zone)
* [Email field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/email-field)
* [Grid](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/grid)
* [Heading](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/heading)
* [Icon](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/icon)
* [Image](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/image)
* [Link](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/link)
* [Menu](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/menu)
* [Money field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/money-field)
* [Number field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/number-field)
* [Ordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/ordered-list)
* [Paragraph](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/paragraph)
* [Password field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/password-field)
* [Query container](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/query-container)
* [Search field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/search-field)
* [Section](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/section)
* [Select](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/select)
* [Spinner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/spinner)
* [Stack](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/stack)
* [Switch](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/switch)
* [Table](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/table)
* [Text](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/text)
* [Text area](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-area)
* [Text field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-field)
* [Thumbnail](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/thumbnail)
* [Tooltip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/tooltip)
* [Url field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/url-field)
* [Unordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/unordered-list)

### Available APIs

* [Print Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/print-action-extension-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that exports selected orders to your ERP system. This example demonstrates how to send multiple selected order IDs to your app backend for batch processing.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeLineItems, setIncludeLineItems] = useState(true);
    const [includeCustomer, setIncludeCustomer] = useState(true);

    const selectedOrders = shopify.data.selected;
    const orderCount = selectedOrders.length;

    const handleExport = async () => {
      setLoading(true);
      setError(null);

      try {
        const orderIds = selectedOrders.map(order => order.id);
        
        const response = await fetch('https://your-app.com/api/erp/export-orders', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderIds,
            options: {
              includeLineItems,
              includeCustomer,
            },
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const result = await response.json();
          setError(result.message || 'Export failed');
        }
      } catch (err) {
        setError('Connection to ERP failed. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Successfully exported {orderCount} order(s) to ERP system!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Summary">
          <s-stack gap="base">
            <s-text>
              <s-text type="strong">{orderCount}</s-text> order(s) selected for export
            </s-text>
            <s-checkbox
              label="Include line items"
              checked={includeLineItems}
              onChange={(e) => setIncludeLineItems(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include customer details"
              checked={includeCustomer}
              onChange={(e) => setIncludeCustomer(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success}
        >
          {loading ? 'Exporting...' : `Export ${orderCount} Order(s)`}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates a custom packing slip for selected orders. This example demonstrates fetching order details using \[direct API]\(/docs/api/admin-extensions/2026-04-rc#direct-api-access) GraphQL endpoint and preparing print-ready content.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includePrices, setIncludePrices] = useState(false);

    const handleGenerateSlip = async () => {
      setLoading(true);
      setError(null);
      const selectedOrders = shopify.data.selected;

      try {
        const query = `
          query GetOrderDetails($id: ID!) {
            order(id: $id) {
              name
              createdAt
              shippingAddress {
                name
                address1
                address2
                city
                provinceCode
                zip
                country
              }
              lineItems(first: 50) {
                edges {
                  node {
                    title
                    quantity
                    sku
                    variant { price }
                  }
                }
              }
            }
          }
        `;

        for (const selected of selectedOrders) {
          const response = await fetch('shopify:admin/api/graphql.json', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({query, variables: {id: selected.id}}),
          });
          const {data} = await response.json();
          
          if (!data?.order) {
            throw new Error('Failed to fetch order details');
          }
        }

        setSuccess(true);
        setTimeout(() => window.print(), 500);
      } catch (err) {
        setError(err.message || 'Failed to generate packing slip');
      } finally {
        setLoading(false);
      }
    };

    const orderCount = shopify.data.selected.length;

    return (
      <s-admin-action heading="Generate Packing Slip">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Packing slip ready! Print dialog opening...
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>{error}</s-banner>
        )}

        <s-section heading="Slip Options">
          <s-stack gap="base">
            <s-text color="subdued">
              Generating packing slip for {orderCount} order{orderCount > 1 ? 's' : ''}
            </s-text>
            <s-checkbox
              label="Include barcode"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include item prices"
              checked={includePrices}
              onChange={(e) => setIncludePrices(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleGenerateSlip}
          disabled={loading || success}
        >
          {loading ? 'Generating...' : 'Generate & Print'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

### Order index selection print action (should render) target

`admin.order-index.selection-print-action.should-render`

Controls the render state of an admin action extension on the orders index page. Use this target to conditionally show or hide your action extension based on the order's properties, such as status, configuration, or specific business requirements.

This target returns a boolean value that determines whether the corresponding action extension appears in the **More actions** menu. The extension evaluates each time the page loads.

### Support Components (0) APIs (1)

### Supported components

\-

### Available APIs

* [Should Render API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/utility-apis/should-render-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that exports selected orders to an external ERP system. This example demonstrates how to send multiple order IDs to your app backend for batch processing and display progress feedback.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeLineItems, setIncludeLineItems] = useState(true);
    const [includeCustomer, setIncludeCustomer] = useState(true);

    const selectedOrders = shopify.data.selected;
    const orderCount = selectedOrders.length;

    const handleExport = async () => {
      setLoading(true);
      setError(null);

      try {
        const orderIds = selectedOrders.map(order => order.id);

        const response = await fetch('https://your-app.com/api/erp/export-orders', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderIds,
            options: {
              includeLineItems,
              includeCustomer,
            },
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const result = await response.json();
          setError(result.message || 'Export failed');
        }
      } catch (err) {
        setError('Connection to ERP failed. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Successfully exported {orderCount} order(s) to ERP system!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Options">
          <s-stack gap="base">
            <s-text color="subdued">
              {orderCount} order(s) selected for export
            </s-text>
            <s-checkbox
              label="Include line items"
              checked={includeLineItems}
              onChange={(e) => setIncludeLineItems(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include customer details"
              checked={includeCustomer}
              onChange={(e) => setIncludeCustomer(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success}
        >
          {loading ? 'Exporting...' : `Export ${orderCount} Order(s)`}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates a custom packing slip PDF for selected orders. This example demonstrates using the \[direct API]\(/docs/api/admin-extensions/2026-04-rc#direct-api-access) using fetch to query order line items and customer shipping details for print-ready document generation.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includePrices, setIncludePrices] = useState(false);

    const handleGenerate = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('shopify:admin/api/graphql.json', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            query: `query GetOrderForPackingSlip($id: ID!) {
              order(id: $id) {
                name
                createdAt
                shippingAddress {
                  name
                  address1
                  city
                  provinceCode
                  zip
                  country
                }
                lineItems(first: 50) {
                  nodes {
                    title
                    quantity
                    sku
                  }
                }
              }
            }`,
            variables: {id: orderId}
          }),
        });

        const {data} = await response.json();
        
        if (data?.order) {
          const itemCount = data.order.lineItems.nodes.length;
          setSuccess(true);
          shopify.close();
        } else {
          setError('Could not fetch order details');
        }
      } catch (err) {
        setError('Failed to generate packing slip');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Generate Packing Slip">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Packing slip generated! Opening print dialog...
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>{error}</s-banner>
        )}

        <s-section heading="Packing Slip Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include barcode for scanning"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Show item prices"
              checked={includePrices}
              onChange={(e) => setIncludePrices(e.currentTarget.checked)}
            />
            <s-text color="subdued">
              Packing slip will include shipping address and line items
            </s-text>
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleGenerate}
          disabled={loading || success}
        >
          {loading ? 'Generating...' : 'Generate & Print'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

***

## Order fulfilled card targets

Use [action targets](https://shopify.dev/docs/api/admin-extensions/2026-04-rc#building-your-extension) to extend the order fulfilled card page with workflows and operations.

### Order fulfilled card action target

`admin.order-fulfilled-card.action.render`

Renders an admin action extension on the order details page. Merchants can access this extension from the **More actions** menu. Use this target to provide workflows that operate on order data, such as syncing with external systems, exporting order information, or managing credit terms.

Extensions at this target can access order data through the `data` property in the [Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/action-extension-api). The action renders in a modal overlay, providing space for multi-step workflows, forms, and confirmations.

### Support Components (45) APIs (1)

### Supported components

* [Admin action](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/settings-and-templates/admin-action)
* [Avatar](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/avatar)
* [Badge](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/badge)
* [Banner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/banner)
* [Box](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/box)
* [Button](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button)
* [Button group](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/button-group)
* [Checkbox](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/checkbox)
* [Chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/chip)
* [Choice list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/choice-list)
* [Clickable](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable)
* [Clickable chip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/clickable-chip)
* [Color field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-field)
* [Color picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/color-picker)
* [Date field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-field)
* [Date picker](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/date-picker)
* [Divider](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/divider)
* [Drop zone](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/drop-zone)
* [Email field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/email-field)
* [Grid](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/grid)
* [Heading](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/heading)
* [Icon](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/icon)
* [Image](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/image)
* [Link](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/link)
* [Menu](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/actions/menu)
* [Money field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/money-field)
* [Number field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/number-field)
* [Ordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/ordered-list)
* [Paragraph](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/paragraph)
* [Password field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/password-field)
* [Query container](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/query-container)
* [Search field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/search-field)
* [Section](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/section)
* [Select](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/select)
* [Spinner](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/feedback-and-status-indicators/spinner)
* [Stack](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/stack)
* [Switch](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/switch)
* [Table](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/table)
* [Text](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/text)
* [Text area](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-area)
* [Text field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/text-field)
* [Thumbnail](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/media-and-visuals/thumbnail)
* [Tooltip](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/typography-and-content/tooltip)
* [Url field](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/forms/url-field)
* [Unordered list](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/web-components/layout-and-structure/unordered-list)

### Available APIs

* [Action Extension API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/core-apis/action-extension-api)

Examples

### Examples

* ####

  ##### Description

  Add an action extension that pushes fulfilled order data to your ERP system. This example demonstrates calling an app backend API with order details and handling the sync response.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [includeTracking, setIncludeTracking] = useState(true);
    const [includeCustomer, setIncludeCustomer] = useState(true);

    const handleExport = async () => {
      setLoading(true);
      setError(null);
      const orderId = shopify.data.selected[0].id;

      try {
        const response = await fetch('https://your-app.com/api/erp/export-order', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({
            orderId,
            includeTracking,
            includeCustomer,
            fulfillmentStatus: 'fulfilled',
          }),
        });

        if (response.ok) {
          setSuccess(true);
          shopify.close();
        } else {
          const data = await response.json();
          setError(data.message || 'Failed to export order to ERP');
        }
      } catch (err) {
        setError('Connection error. Please try again.');
      } finally {
        setLoading(false);
      }
    };

    return (
      <s-admin-action heading="Export to ERP">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Order successfully exported to ERP system!
          </s-banner>
        )}
        {error && (
          <s-banner tone="critical" dismissible={false}>
            {error}
          </s-banner>
        )}

        <s-section heading="Export Options">
          <s-stack gap="base">
            <s-text color="subdued">
              Send this fulfilled order to your ERP for inventory and accounting sync.
            </s-text>
            <s-checkbox
              label="Include tracking information"
              checked={includeTracking}
              onChange={(e) => setIncludeTracking(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include customer details"
              checked={includeCustomer}
              onChange={(e) => setIncludeCustomer(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button
          slot="primary-action"
          onClick={handleExport}
          disabled={loading || success}
        >
          {loading ? 'Exporting...' : 'Export to ERP'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>
          Cancel
        </s-button>
      </s-admin-action>
    );
  };
  ```

* ####

  ##### Description

  Add an action extension that generates a custom packing slip PDF for fulfilled orders. This example demonstrates using the \[direct API]\(/docs/api/admin-extensions/2026-04-rc#direct-api-access) using fetch to query order and fulfillment details, then triggering PDF generation.

  ##### jsx

  ```jsx
  import {render} from 'preact';
  import {useState, useEffect} from 'preact/hooks';

  export default async () => {
    render(<Extension />, document.body);
  };

  const Extension = () => {
    const [loading, setLoading] = useState(false);
    const [generating, setGenerating] = useState(false);
    const [success, setSuccess] = useState(false);
    const [error, setError] = useState(null);
    const [orderData, setOrderData] = useState(null);
    const [includeBarcode, setIncludeBarcode] = useState(true);
    const [includeReturnLabel, setIncludeReturnLabel] = useState(false);

    useEffect(() => {
      fetchOrderDetails();
    }, []);

    const fetchOrderDetails = async () => {
      setLoading(true);
      const orderId = shopify.data.selected[0].id;

      const query = `query GetOrder($id: ID!) {
        order(id: $id) {
          name
          shippingAddress { name address1 city provinceCode zip country }
          fulfillments(first: 1) {
            nodes { trackingInfo { number company } }
          }
          lineItems(first: 10) {
            nodes { title quantity sku }
          }
        }
      }`;

      try {
        const response = await fetch('shopify:admin/api/graphql.json', {
          method: 'POST',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify({query, variables: {id: orderId}}),
        });
        const {data} = await response.json();
        setOrderData(data.order);
      } catch (err) {
        setError('Failed to load order details');
      } finally {
        setLoading(false);
      }
    };

    const handleGenerate = async () => {
      setGenerating(true);
      try {
        await new Promise(resolve => setTimeout(resolve, 1500));
        setSuccess(true);
        shopify.close();
      } catch (err) {
        setError('Failed to generate packing slip');
      } finally {
        setGenerating(false);
      }
    };

    if (loading) {
      return (
        <s-admin-action heading="Generate Packing Slip">
          <s-box padding="large"><s-spinner size="base" /></s-box>
        </s-admin-action>
      );
    }

    return (
      <s-admin-action heading="Generate Packing Slip">
        {success && (
          <s-banner tone="success" dismissible={false}>
            Packing slip generated! Download starting...
          </s-banner>
        )}
        {error && <s-banner tone="critical" dismissible={false}>{error}</s-banner>}

        {orderData && (
          <s-section heading={`Order ${orderData.name}`}>
            <s-stack gap="small">
              <s-text type="strong">Ship to:</s-text>
              <s-text>{orderData.shippingAddress?.name}</s-text>
              <s-text color="subdued">
                {orderData.shippingAddress?.city}, {orderData.shippingAddress?.provinceCode}
              </s-text>
              <s-text color="subdued">{orderData.lineItems.nodes.length} item(s)</s-text>
            </s-stack>
          </s-section>
        )}

        <s-section heading="Options">
          <s-stack gap="base">
            <s-checkbox
              label="Include barcode"
              checked={includeBarcode}
              onChange={(e) => setIncludeBarcode(e.currentTarget.checked)}
            />
            <s-checkbox
              label="Include return shipping label"
              checked={includeReturnLabel}
              onChange={(e) => setIncludeReturnLabel(e.currentTarget.checked)}
            />
          </s-stack>
        </s-section>

        <s-button slot="primary-action" onClick={handleGenerate} disabled={generating || success}>
          {generating ? 'Generating...' : 'Generate PDF'}
        </s-button>
        <s-button slot="secondary-actions" onClick={() => shopify.close()}>Cancel</s-button>
      </s-admin-action>
    );
  };
  ```

### Order fulfilled card action (should render) target

`admin.order-fulfilled-card.action.should-render`

Controls the render state of an admin action extension on the order details page. Use this target to conditionally show or hide your action extension based on the order's properties, such as status, configuration, or specific business requirements.

This target returns a boolean value that determines whether the corresponding action extension appears in the **More actions** menu. The extension evaluates each time the page loads.

### Support Components (0) APIs (1)

### Supported components

\-

### Available APIs

* [Should Render API](https://shopify.dev/docs/api/admin-extensions/2026-04-rc/target-apis/utility-apis/should-render-api)

Examples

### Examples

* ####

  ##### Description

  Show the action only when the app backend confirms tracking information is available and ready for display on the fulfilled order card.

  ##### jsx

  ```jsx
  export default async () => {
    const orderId = shopify.data.selected[0].id;

    try {
      const response = await fetch('https://your-app.com/api/fulfillment/tracking-status', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          orderId,
          checkType: 'tracking_available',
        }),
      });

      if (!response.ok) {
        return { display: false };
      }

      const result = await response.json();

      // Show action if tracking data exists and has updates
      return {
        display: result.hasTracking && result.updatesAvailable,
      };
    } catch (err) {
      console.error('Failed to check tracking status:', err);
      return { display: false };
    }
  };
  ```

* ####

  ##### Description

  Show the fraud risk assessment action only for fulfilled orders that have a high or medium risk level, using the GraphQL Admin API to check the order's risk assessment data.

  ##### jsx

  ```jsx
  export default async () => {
    const orderId = shopify.data.selected[0].id;

    try {
      const response = await fetch('shopify:admin/api/graphql.json', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          query: `query GetOrderRisk($id: ID!) {
            order(id: $id) {
              id
              risk {
                assessments {
                  riskLevel
                  provider {
                    title
                  }
                }
              }
            }
          }`,
          variables: { id: orderId },
        }),
      });

      const { data } = await response.json();
      const assessments = data?.order?.risk?.assessments || [];
      
      // Show action if any assessment indicates HIGH or MEDIUM risk
      const hasElevatedRisk = assessments.some(
        (assessment) => 
          assessment.riskLevel === 'HIGH' || 
          assessment.riskLevel === 'MEDIUM'
      );

      return { display: hasElevatedRisk };
    } catch (err) {
      console.error('Error checking order risk:', err);
      return { display: false };
    }
  };
  ```

***

## Best practices

* **Check fulfillment status before action:** Before displaying fulfillment-related actions, verify the order's [fulfillment status](https://shopify.dev/docs/api/admin-graphql/latest/enums/OrderDisplayFulfillmentStatus) using `displayFulfillmentStatus`. This prevents showing "ship order" actions on already-fulfilled orders or offering refunds on cancelled orders.
* **Batch bulk operations intelligently:** When processing multiple orders, work in batches to stay within [GraphQL query cost limits](https://shopify.dev/docs/api/usage/rate-limits). Display progress for operations on more than 10 orders so merchants can track completion of long-running tasks.
* **Combine risk indicators:** When displaying fraud risk assessments, show both Shopify's native [risk level](https://shopify.dev/docs/api/admin-graphql/latest/enums/OrderRiskLevel) and your app's custom scoring. Provide specific reasons for elevated risk (for example, mismatched billing/shipping, high-value first-time customer, unusual velocity) rather than just a score.
* **Handle financial fields carefully:** Order financial data includes complex fields like refunds, discounts, and tax lines. When calculating totals or displaying financial information, use [`MoneyV2`](https://shopify.dev/docs/api/admin-graphql/latest/objects/MoneyV2) fields (amount and currencyCode) and respect the order's presentment currency for accuracy.
* **Consider order editability:** Orders have different editability states based on their status and payment state. Before showing data modification actions, check if the order can be edited using [order edit workflows](https://shopify.dev/docs/api/admin-graphql/latest/mutations/orderEditBegin) rather than direct mutations.

***

## Limitations

* **Single target per module:** Each `[[extensions.targeting]]` entry in your [TOML configuration](https://shopify.dev/docs/api/admin-extensions/2026-04-rc#configuration) maps one target to one module file.
* **Fulfilled card visibility:** The `admin.order-fulfilled-card.action.render` target only appears on orders fulfilled by your app's fulfillment service. If your app doesn't act as a fulfillment service or an order was fulfilled by Shopify or another fulfillment provider, this target won't appear.
* **Print menu location:** Print actions appear in the **Print** menu, not the **More actions** menu.
* **Block target visibility:** Block extensions must be manually [added and pinned](https://help.shopify.com/manual/apps/working-with-apps#add-app-blocks-to-your-shopify-admin) by merchants before they appear.
* **Block collapse behavior:** Returning `null` from a block extension collapses the block rather than removing it from the page. Blocks can't be fully hidden at runtime.

***
