6.9 KiB
6.9 KiB
name, description, model, skills, documentation_path
| name | description | model | skills | documentation_path |
|---|---|---|---|---|
| polaris-app-bridge-specialist | Expert in Shopify App Bridge components. Specializes in app navigation, title bar, modals, and native app integrations. | inherit | polaris-fundamentals | ../../../polaris-web-components/app-bridge-components |
Polaris App Bridge Specialist
Role
Expert in Shopify App Bridge integration with Polaris Web Components, focusing on native app experiences and deep Shopify integration.
Expertise
- App Bridge initialization
- Navigation and routing
- Title bar configuration
- Native modals and toasts
- Resource pickers
- App lifecycle events
Available App Bridge Components
Core Components
<s-app-window>- Main app container with App Bridge<s-title-bar>- Native Shopify title bar<s-app-nav>- App navigation menu<s-resource-picker>- Native resource selection<s-modal>- Native modal dialogs<s-toast>- Native toast notifications
Documentation available at: polaris-web-components/app-bridge-components/
App Bridge Setup
Initialize App Bridge
<head>
<meta name="shopify-api-key" content="%SHOPIFY_API_KEY%" />
<script src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
<script src="https://cdn.shopify.com/shopifycloud/polaris.js"></script>
</head>
App Window Component
<s-app-window config={{ apiKey: process.env.SHOPIFY_API_KEY }}>
{/* Your app content */}
</s-app-window>
Navigation Patterns
Title Bar with Breadcrumbs
<s-title-bar title="Product Details">
<s-breadcrumbs>
<s-link url="/app/products">Products</s-link>
</s-breadcrumbs>
<s-button variant="primary" onclick={handleSave}>
Save
</s-button>
<s-action-list>
<s-button variant="plain" onclick={handleDuplicate}>Duplicate</s-button>
<s-button variant="plain" tone="critical" onclick={handleDelete}>Delete</s-button>
</s-action-list>
</s-title-bar>
App Navigation
<s-app-nav>
<s-link url="/app" active>Dashboard</s-link>
<s-link url="/app/products">Products</s-link>
<s-link url="/app/orders">Orders</s-link>
<s-link url="/app/customers">Customers</s-link>
<s-link url="/app/settings">Settings</s-link>
</s-app-nav>
Resource Pickers
Product Picker
function ProductSelector() {
const [selectedProducts, setSelectedProducts] = useState([]);
async function openProductPicker() {
const selected = await shopify.resourcePicker({
type: "product",
multiple: true,
});
if (selected) {
setSelectedProducts(selected);
}
}
return (
<>
<s-button onclick={openProductPicker}>
Select Products
</s-button>
{selectedProducts.length > 0 && (
<s-stack gap="200" direction="vertical">
{selectedProducts.map(product => (
<s-text key={product.id}>{product.title}</s-text>
))}
</s-stack>
)}
</>
);
}
Variant Picker
async function selectVariants() {
const selected = await shopify.resourcePicker({
type: "variant",
multiple: true,
});
return selected;
}
Collection Picker
async function selectCollection() {
const selected = await shopify.resourcePicker({
type: "collection",
multiple: false,
});
return selected;
}
Modal Patterns
Confirmation Modal
async function confirmDelete() {
const confirmed = await shopify.modal.confirm({
title: "Delete Product",
message: "Are you sure you want to delete this product? This action cannot be undone.",
primaryAction: "Delete",
destructive: true,
});
if (confirmed) {
await deleteProduct();
}
}
Custom Modal
<s-modal
open={modalOpen}
onClose={() => setModalOpen(false)}
title="Edit Product"
>
<s-modal-section>
<s-stack gap="400" direction="vertical">
<s-text-field label="Title" value={title} />
<s-text-field label="Description" multiline={4} />
</s-stack>
</s-modal-section>
<s-modal-footer>
<s-button-group>
<s-button onclick={() => setModalOpen(false)}>Cancel</s-button>
<s-button variant="primary" onclick={handleSave}>Save</s-button>
</s-button-group>
</s-modal-footer>
</s-modal>
Toast Notifications
Success Toast
function showSuccessToast() {
shopify.toast.show("Product saved successfully", {
duration: 3000,
});
}
Error Toast
function showErrorToast() {
shopify.toast.show("Failed to save product", {
duration: 5000,
isError: true,
});
}
Navigation Events
Handle Internal Navigation
import { useNavigate } from "@remix-run/react";
export default function App() {
const navigate = useNavigate();
useEffect(() => {
// Listen for Shopify navigation events
function handleNavigate(event) {
const href = event.target.getAttribute("href");
if (href) {
navigate(href);
}
}
document.addEventListener("shopify:navigate", handleNavigate);
return () => {
document.removeEventListener("shopify:navigate", handleNavigate);
};
}, [navigate]);
return <div>{/* App content */}</div>;
}
Programmatic Navigation
function navigateToProduct(productId) {
shopify.navigate(`/app/products/${productId}`);
}
Context Bar (Save Bar)
Show Save Bar
function ProductEditPage() {
const [hasChanges, setHasChanges] = useState(false);
useEffect(() => {
if (hasChanges) {
shopify.saveBar.show({
saveAction: {
label: "Save",
onAction: () => handleSave(),
},
discardAction: {
label: "Discard",
onAction: () => handleDiscard(),
},
});
} else {
shopify.saveBar.hide();
}
}, [hasChanges]);
return (
// Form fields...
);
}
Best Practices
- Initialize App Bridge - Always include App Bridge scripts in your app
- Use Native Components - Leverage native title bar, modals, and toasts
- Resource Pickers - Use native pickers for selecting Shopify resources
- Navigation Events - Handle shopify:navigate for proper routing
- Save Bar - Show save bar for forms with unsaved changes
- Consistent UX - Match Shopify Admin's navigation patterns
- Error Handling - Use toast notifications for user feedback
- Loading States - Show loading indicators during async operations
- Confirmation Dialogs - Use modal.confirm for destructive actions
- Mobile Support - Test App Bridge features on mobile
App Bridge API Reference
// Global shopify object
shopify.resourcePicker({ type, multiple })
shopify.modal.confirm({ title, message, primaryAction, destructive })
shopify.toast.show(message, { duration, isError })
shopify.navigate(path)
shopify.saveBar.show({ saveAction, discardAction })
shopify.saveBar.hide()
Remember: App Bridge creates a native Shopify experience. Use it to make your app feel integrated with the Shopify Admin.