app-shopify-polaris-web-components
Shopify Polaris Web Components
Use this skill when building UI for Shopify App Home surfaces using Polaris Web Components.
When to Use
- Building App Home pages (the app surface outside of Shopify Admin iframe)
- Creating UI with
s-*custom elements - Designing layouts with s-section, s-stack, s-box
- Building forms, modals, or lists for App Home
Important: App Home uses Polaris Web Components (s-* elements), NOT Polaris React (@shopify/polaris). These are different technologies.
Polaris React vs Web Components
| Feature | Polaris React | Polaris Web Components |
|---|---|---|
| Use for | Embedded admin apps | App Home surfaces |
| Import | @shopify/polaris |
No import (native elements) |
| Syntax | <Button> |
<s-button> |
| Framework | React components | Custom HTML elements |
Core Components
Page Structure
<s-page heading="Dashboard">
<s-section heading="Overview">
<!-- Content -->
</s-section>
<s-section heading="Settings">
<!-- More content -->
</s-section>
</s-page>
Layout with Stack
<!-- Vertical stack (default) -->
<s-stack direction="block" gap="large">
<s-text>Item 1</s-text>
<s-text>Item 2</s-text>
</s-stack>
<!-- Horizontal stack -->
<s-stack direction="inline" gap="medium" alignItems="center">
<s-button>Cancel</s-button>
<s-button variant="primary">Save</s-button>
</s-stack>
<!-- Stack with justification -->
<s-stack
direction="inline"
justifyContent="space-between"
alignItems="center"
>
<s-text variant="headingMd">Title</s-text>
<s-button>Action</s-button>
</s-stack>
Section (Card-like Container)
Use s-section for grouped content with optional heading:
<!-- Section with heading -->
<s-section heading="Chat Widget Settings">
<s-stack direction="block" gap="medium">
<s-text>Configure your widget appearance.</s-text>
<!-- Form fields -->
</s-stack>
</s-section>
<!-- Section without heading -->
<s-section>
<s-text>Simple content block</s-text>
</s-section>
Box (Generic Layout Container)
Use s-box for padding, borders, and spacing - NOT for cards:
<!-- Box with padding -->
<s-box padding="large">
<s-text>Padded content</s-text>
</s-box>
<!-- Box with border -->
<s-box
padding="medium"
borderWidth="base"
borderRadius="base"
>
<s-text>Bordered content</s-text>
</s-box>
<!-- Box for spacing -->
<s-box paddingBlockStart="large">
<s-text>Content with top margin</s-text>
</s-box>
Rule: Use s-section for card-like containers, s-box for layout/spacing only.
Buttons
<!-- Primary action -->
<s-button variant="primary" type="submit">
Save Settings
</s-button>
<!-- Default button -->
<s-button>Cancel</s-button>
<!-- Destructive -->
<s-button variant="primary" tone="critical">
Delete
</s-button>
<!-- Disabled -->
<s-button disabled>Unavailable</s-button>
<!-- With click handler (in JS) -->
<s-button id="save-btn">Save</s-button>
<script>
document.getElementById('save-btn').addEventListener('click', handleSave);
</script>
Text
<!-- Headings -->
<s-text variant="headingLg">Large Heading</s-text>
<s-text variant="headingMd">Medium Heading</s-text>
<s-text variant="headingSm">Small Heading</s-text>
<!-- Body text -->
<s-text>Default body text</s-text>
<s-text variant="bodySm">Small body text</s-text>
<!-- Tones -->
<s-text tone="subdued">Muted text</s-text>
<s-text tone="critical">Error text</s-text>
<s-text tone="success">Success text</s-text>
Banner
<!-- Info banner -->
<s-banner>
<p>This is an informational message.</p>
</s-banner>
<!-- Critical banner -->
<s-banner tone="critical">
<p>Something went wrong. Please try again.</p>
</s-banner>
<!-- Success banner -->
<s-banner tone="success">
<p>Settings saved successfully!</p>
</s-banner>
<!-- Dismissible banner -->
<s-banner tone="warning" onDismiss="handleDismiss">
<p>Your trial ends in 3 days.</p>
</s-banner>
Link
<s-link href="/settings">Go to Settings</s-link>
<s-link href="https://shopify.dev" external>
Documentation
</s-link>
Form Elements
<!-- Text field -->
<s-text-field
label="Store name"
value="My Store"
helpText="This appears in your widget"
></s-text-field>
<!-- Select -->
<s-select label="Language">
<option value="en">English</option>
<option value="es">Spanish</option>
</s-select>
<!-- Checkbox -->
<s-checkbox label="Enable notifications" checked></s-checkbox>
Common Patterns
Settings Page
<s-page heading="Settings">
<s-stack direction="block" gap="large">
<s-section heading="General">
<s-stack direction="block" gap="medium">
<s-text-field
label="Welcome message"
value="Hello! How can we help?"
></s-text-field>
<s-checkbox label="Enable auto-reply"></s-checkbox>
</s-stack>
</s-section>
<s-section heading="Appearance">
<s-stack direction="block" gap="medium">
<s-select label="Theme">
<option value="light">Light</option>
<option value="dark">Dark</option>
</s-select>
</s-stack>
</s-section>
<s-box paddingBlockStart="large">
<s-stack direction="inline" gap="medium" justifyContent="flex-end">
<s-button>Cancel</s-button>
<s-button variant="primary">Save</s-button>
</s-stack>
</s-box>
</s-stack>
</s-page>
Empty State
<s-section>
<s-stack direction="block" gap="medium" alignItems="center">
<s-text variant="headingMd">No campaigns yet</s-text>
<s-text tone="subdued">
Create your first campaign to get started.
</s-text>
<s-button variant="primary">Create Campaign</s-button>
</s-stack>
</s-section>
List with Actions
<s-section heading="Campaigns">
<s-stack direction="block" gap="none">
<s-box padding="medium" borderBlockEnd="base">
<s-stack direction="inline" justifyContent="space-between" alignItems="center">
<s-stack direction="block" gap="extraSmall">
<s-text variant="headingSm">Welcome Series</s-text>
<s-text tone="subdued">Active • 1,234 sent</s-text>
</s-stack>
<s-button>Edit</s-button>
</s-stack>
</s-box>
<s-box padding="medium" borderBlockEnd="base">
<s-stack direction="inline" justifyContent="space-between" alignItems="center">
<s-stack direction="block" gap="extraSmall">
<s-text variant="headingSm">Abandoned Cart</s-text>
<s-text tone="subdued">Paused • 567 sent</s-text>
</s-stack>
<s-button>Edit</s-button>
</s-stack>
</s-box>
</s-stack>
</s-section>
TypeScript Support
Add types for s-* components in your tsconfig.json:
{
"compilerOptions": {
"types": ["@shopify/polaris-types"]
}
}
Best Practices
- Use s-section for cards - Not s-box
- Use s-box for layout only - Padding, borders, spacing
- Prefer s- over custom divs* - Only use div when s-* can't achieve the layout
- Use semantic structure - s-page > s-section > content
- Consistent spacing - Use gap props, not manual margins
- Check the docs - Components have many props not shown here
When to Use Custom Styles
Only use plain div and inline styles when:
- The user explicitly requests it
- After trying s-* components and they can't achieve the required layout
- For very specific visual effects not supported by Polaris
References
More from niccos-shopify-workspace/shopify-cursor-skills
theme-shopify-liquid-templates
Liquid template best practices for Shopify themes - snippets, logic, image handling, and SVG usage. Use when writing or modifying Liquid templates in Shopify themes.
79theme-shopify-css-guidelines
CSS naming conventions (BEM), nesting rules, and encapsulation guidelines for Shopify themes. Use when writing CSS for Shopify theme sections.
50theme-shopify-section-structure
Shopify theme section structure, file organization, and schema requirements. Use when creating or modifying Shopify theme sections.
49theme-shopify-javascript-standards
JavaScript standards for Shopify themes - custom elements, file structure, and best practices. Use when writing JavaScript for Shopify theme sections.
43app-shopify-admin-graphql
Execute Shopify Admin API calls via GraphQL in Shopify Remix apps. Use when querying or mutating Shopify data (customers, orders, products, shop, segments, subscriptions), when writing GraphQL for the Admin API, or when handling throttling and retries.
35theme-shopify-html-data-comments
HTML structure, data attributes, and commenting guidelines for Shopify themes. Use when structuring HTML markup and adding comments to Shopify theme code.
32