Version 2025-07 is the last API version to support React-based UI components. Later versions use web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the migration guide to upgrade your extension.
Pressable
The Pressable component creates a clickable area around its children without adding any visible button or link styling. It combines the layout capabilities of Box with the navigation and click handling of Link, making it useful for building custom interactive elements like clickable cards or list items.
For standard actions with button styling, use Button.
Supported targets
- admin.
abandoned-checkout-details. action. render - admin.
abandoned-checkout-details. block. render - admin.
catalog-details. action. render - admin.
catalog-details. block. render - admin.
collection-details. action. render - admin.
collection-details. block. render - admin.
collection-index. action. render - admin.
company-details. action. render - admin.
company-details. block. render - admin.
company-location-details. block. render - admin.
customer-details. action. render - admin.
customer-details. block. render - admin.
customer-index. action. render - admin.
customer-index. selection-action. render - admin.
customer-segment-details. action. render - admin.
discount-details. action. render - admin.
discount-details. function-settings. render - admin.
discount-index. action. render - admin.
draft-order-details. action. render - admin.
draft-order-details. block. render - admin.
draft-order-index. action. render - admin.
draft-order-index. selection-action. render - admin.
gift-card-details. action. render - admin.
gift-card-details. block. render - admin.
order-details. action. render - admin.
order-details. block. render - admin.
order-details. print-action. render - admin.
order-fulfilled-card. action. render - admin.
order-index. action. render - admin.
order-index. selection-action. render - admin.
order-index. selection-print-action. render - admin.
product-details. action. render - admin.
product-details. block. render - admin.
product-details. configuration. render - admin.
product-details. print-action. render - admin.
product-details. reorder. render - admin.
product-index. action. render - admin.
product-index. selection-action. render - admin.
product-index. selection-print-action. render - admin.
product-purchase-option. action. render - admin.
product-variant-details. action. render - admin.
product-variant-details. block. render - admin.
product-variant-details. configuration. render - admin.
product-variant-purchase-option. action. render - admin.
settings. order-routing-rule. render - admin.
settings. validation. render
Supported targets
- admin.
abandoned-checkout-details. action. render - admin.
abandoned-checkout-details. block. render - admin.
catalog-details. action. render - admin.
catalog-details. block. render - admin.
collection-details. action. render - admin.
collection-details. block. render - admin.
collection-index. action. render - admin.
company-details. action. render - admin.
company-details. block. render - admin.
company-location-details. block. render - admin.
customer-details. action. render - admin.
customer-details. block. render - admin.
customer-index. action. render - admin.
customer-index. selection-action. render - admin.
customer-segment-details. action. render - admin.
discount-details. action. render - admin.
discount-details. function-settings. render - admin.
discount-index. action. render - admin.
draft-order-details. action. render - admin.
draft-order-details. block. render - admin.
draft-order-index. action. render - admin.
draft-order-index. selection-action. render - admin.
gift-card-details. action. render - admin.
gift-card-details. block. render - admin.
order-details. action. render - admin.
order-details. block. render - admin.
order-details. print-action. render - admin.
order-fulfilled-card. action. render - admin.
order-index. action. render - admin.
order-index. selection-action. render - admin.
order-index. selection-print-action. render - admin.
product-details. action. render - admin.
product-details. block. render - admin.
product-details. configuration. render - admin.
product-details. print-action. render - admin.
product-details. reorder. render - admin.
product-index. action. render - admin.
product-index. selection-action. render - admin.
product-index. selection-print-action. render - admin.
product-purchase-option. action. render - admin.
product-variant-details. action. render - admin.
product-variant-details. block. render - admin.
product-variant-details. configuration. render - admin.
product-variant-purchase-option. action. render - admin.
settings. order-routing-rule. render - admin.
settings. validation. render
Anchor to PropertiesProperties
Props for the Pressable component, which combines the layout capabilities of Box with the interactive behavior of Link. Use Pressable when you need a custom interactive area that can navigate to a URL or respond to press events while supporting flexible layout and styling options.
- Anchor to accessibilityLabelaccessibilityLabelaccessibilityLabelstringstring
A label that describes the purpose or contents of the element. When set, it will be announced to users using assistive technologies and will provide them with more context. When set, any children or
labelsupplied won't be announced to screen readers.- Anchor to accessibilityRoleaccessibilityRoleaccessibilityRoleAccessibilityRoleAccessibilityRoleDefault: 'generic'Default: 'generic'
The semantic meaning of the component’s content. When set, the role will be used by assistive technologies to help users navigate the page.
- Anchor to blockSizeblockSizeblockSizenumber | `${number}%`number | `${number}%`
The block size (height in horizontal writing modes) of the element.
number: The size in pixels.`${number}%`: The size as a percentage of the parent container's block size.
Learn more about the block-size property.
- Anchor to displaydisplaydisplay'auto' | 'none''auto' | 'none'Default: 'auto'Default: 'auto'
Whether the element is rendered and takes up space in the layout.
auto: The element is rendered normally and participates in layout.none: The element isn't rendered at all and doesn't take up any space. Use this to conditionally hide content without removing it from the component tree.
- Anchor to hrefhrefhrefstringstring
The URL to link to. If set, the link will navigate to the specified location after executing the
callback. Use this prop for standard navigation links within or outside the Shopify admin.- Anchor to idididstringstring
A unique identifier for the link. When not set, a globally unique value will be used instead.
- Anchor to inlineSizeinlineSizeinlineSizenumber | `${number}%`number | `${number}%`
The inline size (width in horizontal writing modes) of the element.
number: The size in pixels.`${number}%`: The size as a percentage of the parent container's inline size.
Learn more about the inline-size property.
- Anchor to langlanglangstringstring
An alias for
language. The language of the link's text content. Use this when the link text is in a different language than the rest of the page so assistive technologies can invoke the correct pronunciation. Must be a valid IANA language subtag.- Anchor to languagelanguagelanguagestringstring
The language of the link's text content. Use this when the link text is in a different language than the rest of the page so assistive technologies can invoke the correct pronunciation. Must be a valid IANA language subtag.
- Anchor to maxBlockSizemaxBlockSizemaxBlockSizenumber | `${number}%`number | `${number}%`
The maximum block size (maximum height in horizontal writing modes). The element won't grow taller than this value even if its content is longer.
number: The size in pixels.`${number}%`: The size as a percentage of the parent container's block size.
Learn more about the max-block-size property.
- Anchor to maxInlineSizemaxInlineSizemaxInlineSizenumber | `${number}%`number | `${number}%`
The maximum inline size (maximum width in horizontal writing modes). The element won't grow wider than this value.
number: The size in pixels.`${number}%`: The size as a percentage of the parent container's inline size.
Learn more about the max-inline-size property.
- Anchor to minBlockSizeminBlockSizeminBlockSizenumber | `${number}%`number | `${number}%`
The minimum block size (minimum height in horizontal writing modes). The element won't shrink smaller than this value even if its content is shorter.
number: The size in pixels.`${number}%`: The size as a percentage of the parent container's block size.
Learn more about the min-block-size property.
- Anchor to minInlineSizeminInlineSizeminInlineSizenumber | `${number}%`number | `${number}%`
The minimum inline size (minimum width in horizontal writing modes). The element won't shrink narrower than this value.
number: The size in pixels.`${number}%`: The size as a percentage of the parent container's inline size.
Learn more about the min-inline-size property.
- Anchor to onClickonClickonClick() => void() => void
A callback that fires when the link is pressed. If
hrefis set, the callback executes first and then the link navigates to the specified location.- Anchor to onPressonPressonPress() => void() => void
An alias for
. A callback that fires when the link is pressed. Ifhrefis set, the callback executes first and then the link navigates to the specified location.- Anchor to paddingpaddingpaddingMaybeAllBoxEdgesShorthandProperty<SpacingKeyword | boolean>MaybeAllBoxEdgesShorthandProperty<SpacingKeyword | boolean>
The padding on all edges of the element, using a shorthand syntax. You can specify one to four values following the CSS shorthand convention.
When set to
true, applies a default padding appropriate for the component.- Anchor to paddingBlockpaddingBlockpaddingBlockMaybeTwoBoxEdgesShorthandProperty<SpacingKeyword | boolean>MaybeTwoBoxEdgesShorthandProperty<SpacingKeyword | boolean>
The padding on the block-start and block-end edges. When set to
true, applies a default block padding appropriate for the component.Learn more about the padding-block property.
- Anchor to paddingBlockEndpaddingBlockEndpaddingBlockEndSpacingKeyword | booleanSpacingKeyword | boolean
The padding on the block-end edge (the bottom edge in horizontal writing modes). When set to
true, applies a default padding appropriate for the component.Learn more about the padding-block-end property.
- Anchor to paddingBlockStartpaddingBlockStartpaddingBlockStartSpacingKeyword | booleanSpacingKeyword | boolean
The padding on the block-start edge (the top edge in horizontal writing modes). When set to
true, applies a default padding appropriate for the component.Learn more about the padding-block-start property.
- Anchor to paddingInlinepaddingInlinepaddingInlineMaybeTwoBoxEdgesShorthandProperty<SpacingKeyword | boolean>MaybeTwoBoxEdgesShorthandProperty<SpacingKeyword | boolean>
The padding on the inline-start and inline-end edges. When set to
true, applies a default inline padding appropriate for the component.Learn more about the padding-inline property.
- Anchor to paddingInlineEndpaddingInlineEndpaddingInlineEndSpacingKeyword | booleanSpacingKeyword | boolean
The padding on the inline-end edge (the right edge in left-to-right writing modes). When set to
true, applies a default padding appropriate for the component.Learn more about the padding-inline-end property.
- Anchor to paddingInlineStartpaddingInlineStartpaddingInlineStartSpacingKeyword | booleanSpacingKeyword | boolean
The padding on the inline-start edge (the left edge in left-to-right writing modes). When set to
true, applies a default padding appropriate for the component.Learn more about the padding-inline-start property.
- Anchor to targettargettarget'_blank' | '_self''_blank' | '_self'Default: '_self'Default: '_self'
The browsing context for opening the linked URL.
_blank: Opens the link in a new tab or window._self: Opens the link in the current page (default behavior).
- Anchor to tototostringstring
An alias for
href. If set, the link will navigate to the specified location after executing thecallback.- Anchor to tonetonetone'default' | 'inherit' | 'critical''default' | 'inherit' | 'critical'Default: 'default'Default: 'default'
The color of the link text.
default: Uses the standard link color to indicate an interactive element.inherit: Takes the color value from its parent, giving the link a monochrome appearance. Pair this with another stylistic treatment, like an underline, to differentiate the link from normal text.critical: Uses a critical (destructive) color to indicate a potentially dangerous action, such as deleting a resource.
AccessibilityRole
The set of accessibility roles that can be applied to layout components to convey semantic meaning to assistive technologies. Each role maps to a corresponding HTML element or ARIA role in web-based hosts. - `main`: The primary content of the page. - `header`: A header section of the page. - `footer`: A section for copyright information, navigation links, and privacy statements. - `section`: A generic section; should have a heading or accessible label. - `aside`: A supporting section related to the main content. - `navigation`: A major group of navigation links. - `ordered-list`: A list of ordered items. - `list-item`: An item inside a list. - `list-item-separator`: A divider that separates items in a list. - `unordered-list`: A list of unordered items. - `separator`: A divider separating sections of content. - `status`: A live region with advisory information that isn't urgent enough to be an alert. - `alert`: Important, usually time-sensitive information. - `generic`: A nameless container with no semantic meaning on its own.
'main' | 'header' | 'footer' | 'section' | 'aside' | 'navigation' | 'ordered-list' | 'list-item' | 'list-item-separator' | 'unordered-list' | 'separator' | 'status' | 'alert' | 'generic'MaybeAllBoxEdgesShorthandProperty
A shorthand type that accepts one to four spacing values following the CSS box-edge shorthand convention (block-start, inline-end, block-end, inline-start). - One value (such as `base`): Applied to all four edges. - Two values (such as `base none`): The first is applied to block-start and block-end, the second to inline-start and inline-end. - Three values (such as `base none large`): The first is block-start, the second is inline-start and inline-end, the third is block-end. - Four values (such as `base none large small`): Applied to block-start, inline-end, block-end, and inline-start respectively.
T | `${T} ${T}` | `${T} ${T} ${T}` | `${T} ${T} ${T} ${T}`SpacingKeyword
A keyword that maps to a predefined spacing value from the Shopify admin design system. Use these instead of pixel values to ensure consistent spacing throughout the UI. - `none`: No spacing (0px). - `small`: A compact amount of spacing, suitable for tight layouts. - `base`: The default spacing, appropriate for most layouts. - `large`: A generous amount of spacing, used to create visual separation.
'none' | 'small' | 'base' | 'large'MaybeTwoBoxEdgesShorthandProperty
A shorthand type that accepts one or two spacing values, representing the start and end edges of a single axis (block or inline). - One value (such as `base`): Applied to both the start and end edges. - Two values (such as `base none`): The first is applied to the start edge, the second to the end edge.
T | `${T} ${T}`Anchor to ExamplesExamples
Anchor to Build custom action rowsBuild custom action rows
Trigger an inventory sync or a data export from icon-labeled action rows. This example uses Pressable with onPress callbacks and Icon labels to create clickable rows that call backend APIs without visible button styling.
Build custom action rows
 labels to create clickable rows that call backend APIs without visible button styling.](https://cdn.shopify.com/shopifycloud/shopify-dev/production/assets/assets/images/templated-apis-screenshots/admin-extensions/2025-07/pressable-default-BsRqutbG.png)
Build custom action rows
React
import {reactExtension, useApi, Pressable, Text, Icon, InlineStack, BlockStack} from '@shopify/ui-extensions-react/admin';
function App() {
const {data} = useApi('admin.product-details.block.render');
const productId = data.selected[0]?.id;
return (
<BlockStack gap>
<Text fontWeight="bold">Quick actions</Text>
<Pressable
padding="base"
onPress={async () => {
await fetch('/api/products/sync', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId}),
});
}}
>
<InlineStack gap blockAlignment="center">
<Icon name="RefreshMajor" accessibilityLabel="" />
<Text>Sync inventory now</Text>
</InlineStack>
</Pressable>
<Pressable
padding="base"
onPress={async () => {
await fetch('/api/products/export', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId}),
});
}}
>
<InlineStack gap blockAlignment="center">
<Icon name="ExportMinor" accessibilityLabel="" />
<Text>Export product data</Text>
</InlineStack>
</Pressable>
</BlockStack>
);
}
export default reactExtension(
'admin.product-details.block.render',
() => <App />,
);TS
import {extension, Pressable, Text, Icon, InlineStack, BlockStack} from '@shopify/ui-extensions/admin';
export default extension(
'admin.product-details.block.render',
(root, api) => {
const {data} = api;
const productId = data.selected[0]?.id;
const stack = root.createComponent(BlockStack, {gap: true});
const heading = root.createComponent(Text, {fontWeight: 'bold'}, 'Quick actions');
const syncAction = root.createComponent(Pressable, {
padding: 'base',
onPress: async () => {
await fetch('/api/products/sync', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId}),
});
},
});
const syncRow = root.createComponent(InlineStack, {gap: true, blockAlignment: 'center'});
const syncIcon = root.createComponent(Icon, {name: 'RefreshMajor', accessibilityLabel: ''});
const syncText = root.createComponent(Text, {}, 'Sync inventory now');
syncRow.appendChild(syncIcon);
syncRow.appendChild(syncText);
syncAction.appendChild(syncRow);
const exportAction = root.createComponent(Pressable, {
padding: 'base',
onPress: async () => {
await fetch('/api/products/export', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId}),
});
},
});
const exportRow = root.createComponent(InlineStack, {gap: true, blockAlignment: 'center'});
const exportIcon = root.createComponent(Icon, {name: 'ExportMinor', accessibilityLabel: ''});
const exportText = root.createComponent(Text, {}, 'Export product data');
exportRow.appendChild(exportIcon);
exportRow.appendChild(exportText);
exportAction.appendChild(exportRow);
stack.appendChild(heading);
stack.appendChild(syncAction);
stack.appendChild(exportAction);
root.appendChild(stack);
},
);Anchor to Create a clickable product cardCreate a clickable product card
Use href and target props to make a Pressable behave as a link, wrapping rich content like Image and text. This example creates a clickable card that opens the product's storefront page in a new tab.
Create a clickable product card
React
import {reactExtension, useApi, Pressable, Text, Image, BlockStack} from '@shopify/ui-extensions-react/admin';
function App() {
const {data} = useApi('admin.product-details.block.render');
const productId = data.selected[0]?.id;
const numericId = productId?.split('/').pop();
return (
<BlockStack gap>
<Pressable
href={`https://your-store.myshopify.com/products/${numericId}`}
target="_blank"
padding="base"
>
<Image
source="https://cdn.shopify.com/s/files/placeholder-images/product.png"
accessibilityLabel="Product preview"
/>
<Text fontWeight="bold">View on storefront</Text>
<Text>Opens the live product page in a new tab</Text>
</Pressable>
</BlockStack>
);
}
export default reactExtension(
'admin.product-details.block.render',
() => <App />,
);TS
import {extension, Pressable, Text, Image, BlockStack} from '@shopify/ui-extensions/admin';
export default extension(
'admin.product-details.block.render',
(root, api) => {
const {data} = api;
const productId = data.selected[0]?.id;
const numericId = productId?.split('/').pop();
const stack = root.createComponent(BlockStack, {gap: true});
const card = root.createComponent(Pressable, {
href: `https://your-store.myshopify.com/products/${numericId}`,
target: '_blank',
padding: 'base',
});
const image = root.createComponent(Image, {
source: 'https://cdn.shopify.com/s/files/placeholder-images/product.png',
accessibilityLabel: 'Product preview',
});
const title = root.createComponent(Text, {fontWeight: 'bold'}, 'View on storefront');
const description = root.createComponent(Text, {}, 'Opens the live product page in a new tab');
card.appendChild(image);
card.appendChild(title);
card.appendChild(description);
stack.appendChild(card);
root.appendChild(stack);
},
);Anchor to Add accessible interactive regionsAdd accessible interactive regions
Label custom tappable areas for screen readers using accessibilityLabel. This example renders warehouse location rows with Badge indicators, where each row announces its stock level and location name to assistive technology.
Add accessible interactive regions
React
import {reactExtension, Pressable, Text, Badge, InlineStack, BlockStack} from '@shopify/ui-extensions-react/admin';
function App() {
return (
<BlockStack gap>
<Text fontWeight="bold">Warehouse locations</Text>
<Pressable
padding="base"
accessibilityLabel="View New York warehouse details — 142 units in stock"
onPress={() => console.log('Card pressed')}
>
<InlineStack gap blockAlignment="center">
<Text>New York</Text>
<Badge tone="success">142 units</Badge>
</InlineStack>
</Pressable>
<Pressable
padding="base"
accessibilityLabel="View Los Angeles warehouse details — 3 units in stock, low stock"
onPress={() => console.log('Card pressed')}
>
<InlineStack gap blockAlignment="center">
<Text>Los Angeles</Text>
<Badge tone="warning">3 units</Badge>
</InlineStack>
</Pressable>
</BlockStack>
);
}
export default reactExtension(
'admin.product-details.block.render',
() => <App />,
);TS
import {extension, Pressable, Text, Badge, InlineStack, BlockStack} from '@shopify/ui-extensions/admin';
export default extension(
'admin.product-details.block.render',
(root) => {
const stack = root.createComponent(BlockStack, {gap: true});
const heading = root.createComponent(Text, {fontWeight: 'bold'}, 'Warehouse locations');
const location1 = root.createComponent(Pressable, {
padding: 'base',
accessibilityLabel: 'View New York warehouse details — 142 units in stock',
onPress: () => console.log('Card pressed'),
});
const row1 = root.createComponent(InlineStack, {gap: true, blockAlignment: 'center'});
const name1 = root.createComponent(Text, {}, 'New York');
const badge1 = root.createComponent(Badge, {tone: 'success'}, '142 units');
row1.appendChild(name1);
row1.appendChild(badge1);
location1.appendChild(row1);
const location2 = root.createComponent(Pressable, {
padding: 'base',
accessibilityLabel: 'View Los Angeles warehouse details — 3 units in stock, low stock',
onPress: () => console.log('Card pressed'),
});
const row2 = root.createComponent(InlineStack, {gap: true, blockAlignment: 'center'});
const name2 = root.createComponent(Text, {}, 'Los Angeles');
const badge2 = root.createComponent(Badge, {tone: 'warning'}, '3 units');
row2.appendChild(name2);
row2.appendChild(badge2);
location2.appendChild(row2);
stack.appendChild(heading);
stack.appendChild(location1);
stack.appendChild(location2);
root.appendChild(stack);
},
);Anchor to Best practicesBest practices
- Use for custom interactive layouts: Pressable is ideal when you need to make a group of elements clickable as a single unit, such as a card that navigates to a detail page. For standard actions, prefer Button or Link.
- Pair with visual hover cues: Pressable changes the cursor on hover, but consider combining it with other visual feedback so the interactive area is obvious to all users.
- Avoid nesting interactive elements: Don't place Button or Link components inside a Pressable. Nesting interactive elements creates confusing behavior for keyboard and screen reader users and can lead to unexpected click handling.
Anchor to LimitationsLimitations
- Pressable doesn't render any visual styling beyond a cursor change on hover. All visual feedback, such as background color changes or borders, must be handled by the child components.
- Pressable doesn't support form submission or reset behavior. Use a Button to submit or reset forms.
- When using
hreffor navigation, theonClickcallback fires before navigation. You can't conditionally prevent navigation from within the callback.