Best Practices

Plugin Design Guidelines

Ten guidelines for building plugins that feel native to the admin — component usage, dark mode support, loading states, empty states, and navigation patterns.

Plugins that follow these guidelines feel like a natural part of the admin rather than an embedded foreign experience.

1. Use the WUI component library

The pre-built components match the admin's design language. Use them instead of building custom components for common patterns — cards, badges, banners, buttons, and typography are all covered.

2. Follow the page pattern

Every plugin page should start with Page and PageHeader:

<Page>
  <PageHeader title="Page Title" description="What this page does" />
  {/* Content */}
</Page>

The description is optional but helps merchants understand the purpose of the page at a glance.

3. Define clear sidebar navigation

In your whatalo.app.ts manifest:

  • Use descriptive, action-oriented page titles
  • Keep the first page as your main dashboard
  • Use a dedicated settings page for configuration rather than mixing it into the dashboard
  • Short labels help when the sidebar is narrow

4. Support dark mode

Always use useThemeSync() and reference --wui-* CSS tokens for colors. Never hardcode hex values — the same component must look correct in both light and dark mode.

5. Handle narrow viewports

The admin is responsive. Your plugin should adapt gracefully when the iframe is narrow. Prefer BlockStack (vertical) over InlineStack (horizontal) for primary content, since vertical layouts adapt better to narrow containers.

6. Show loading states

Always render a loading indicator while fetching data. Never show an empty or broken layout while a request is in flight:

{loading ? (
  <Spinner />
) : (
  <DataTable data={orders} />
)}

7. Show helpful empty states

When a list or dataset has no items, explain why and suggest a next step:

{orders.length === 0 ? (
  <Banner status="info" title="No orders yet">
    Orders will appear here once merchants start placing them.
  </Banner>
) : (
  <OrderList orders={orders} />
)}

8. Confirm actions with feedback

Use toasts to confirm that an action completed. Never leave the merchant wondering whether their action worked:

const handleSave = async () => {
  await saveSettings(data);
  bridge.toast.show("Settings saved", { variant: "success" });
};

9. Keep navigation simple

Use switch(currentPage) for routing between plugin pages. React Router and client-side URL manipulation are not necessary — the bridge delivers the current page as a string from the manifest.

Each page should be self-contained and not depend on state passed from another page.

10. Write clear copy

  • Use action-oriented button labels: "Save changes" not "Submit"
  • Page titles should describe what the page does, not what it is
  • Use the merchant's locale (bridge.locale) when formatting dates and numbers
  • Avoid technical jargon in user-facing text

On this page