Skip to main content

Migrate Disclosure to the Polaris details component

The Polaris details component provides expandable and collapsible content sections. It replaces the previous Disclosure component and is available as <s-details> in API versions 2025-10 and newer.

The previous Disclosure component paired an activator child (a Button, Pressable, Checkbox, or Switch with toggles) with content children that expanded or collapsed. The Polaris <s-details> component is a single element that renders both summary and content through its own children.


The previous pattern of using Disclosure as a wrapper with a Button toggles activator is now handled by an <s-button> with command="--toggle" and commandFor pointing at an <s-details> element by id. The button keeps the same visual treatment as before, while <s-details> carries the disclosed content.

Migrating basic disclosure to s-details

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

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

function Extension() {
return (
<>
<s-button command="--toggle" commandFor="order-details" variant="primary">
Show order details
</s-button>
<s-details id="order-details">
<s-text>Your order includes free shipping and gift wrapping.</s-text>
</s-details>
</>
);
}
import {
reactExtension,
Button,
Disclosure,
Text,
View,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
return (
<Disclosure>
<Button toggles="order-details">Show order details</Button>
<View id="order-details">
<Text>Your order includes free shipping and gift wrapping.</Text>
</View>
</Disclosure>
);
}

If you'd prefer the native disclosure widget over a button activator, <s-details> also supports an <s-summary> child that renders an inline expandable summary.

Anchor to Separate activator with commandSeparate activator with command

If you need a trigger element that is separate from the content (for example, a Checkbox or Switch toggling a content block), use command and commandFor on the activator, pointing at the <s-details> by id.

Migrating separate activator pattern

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

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

function Extension() {
return (
<>
<s-switch
label="Add gift wrapping"
command="--toggle"
commandFor="gift-options"
/>
<s-details id="gift-options">
<s-text>
We'll wrap your order in premium gift paper with a handwritten note.
</s-text>
</s-details>
</>
);
}
import {
reactExtension,
Disclosure,
Switch,
Text,
View,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
return (
<Disclosure>
<Switch toggles="gift-options">Add gift wrapping</Switch>
<View id="gift-options">
<Text>
We'll wrap your order in premium gift paper with a handwritten note.
</Text>
</View>
</Disclosure>
);
}

The following properties are different in the Polaris details component.

The previous Disclosure defaultOpen prop accepted boolean, string, or string[] values to control which content blocks start expanded. The Polaris defaultOpen prop is a simple boolean.

Previous valueNew valueMigration notes
{true}defaultOpenNo change for simple boolean usage.
"section-id"defaultOpenUse one <s-details> per section and set defaultOpen on each one that should start expanded.
{["id-1", "id-2"]}defaultOpen on each <s-details>Multiple open sections require separate <s-details> elements.

The previous Disclosure transition prop is now called toggleTransition.

Previous valueNew valueMigration notes
'none'toggleTransition="none"Disables the transition animation.
Not settoggleTransition="auto"'auto' is the default.

The previous controlled pattern using open and onToggle is now handled through the open property and the toggle / aftertoggle events.

Previous patternNew patternMigration notes
open={state} + onToggle.open property + onToggle / onAfterToggle eventsopen is a JS property that does not reflect to an attribute.

Migrating controlled disclosure

import '@shopify/ui-extensions/preact';
import {render} from 'preact';
import {useState} from 'preact/hooks';

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

function Extension() {
const [open, setOpen] = useState(false);

return (
<>
<s-button onClick={() => setOpen(!open)} variant="primary">
{open ? 'Hide' : 'Show'} details
</s-button>
<s-details open={open} onToggle={(event) => setOpen(event.newState === 'open')}>
<s-text>Your order includes free shipping.</s-text>
</s-details>
</>
);
}
import {useState} from 'react';
import {
reactExtension,
Button,
Disclosure,
Text,
View,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
const [open, setOpen] = useState(false);

return (
<Disclosure open={open} onToggle={(openIds) => setOpen(openIds.length > 0)}>
<Button toggles="details">
{open ? 'Hide' : 'Show'} details
</Button>
<View id="details">
<Text>Your order includes free shipping.</Text>
</View>
</Disclosure>
);
}

The following properties from the previous Disclosure component are no longer needed:

  • toggles on activator children — replaced by command and commandFor attributes on the activator element, or by using <s-summary> inside <s-details>. See the separate activator pattern above.

The Polaris details component introduces the following new properties:

New propTypeDescription
toggleTransition'auto' | 'none'Controls the expand/collapse animation. Default is 'auto'. Replaces the previous transition prop.

Was this page helpful?