Primitives
View on GitHubReact wrappers for Shopify Polaris Web Components.
These are thin React adapters around Polaris Web Components. They normalize boolean props, handle custom events, and provide typed slots — making Polaris ergonomic in React without replacing the underlying components.
Primitives are open source and available on GitHub.
What you get
Component files
TypeScript source you own and can modify
Storybook stories
Interactive examples for every component and variant
Type definitions
Full TypeScript types for props and events
Add event handlers, slots, or sub-components beyond the base web component.
Normalizes boolean props and typed slots for React. No new API surface.
TypeScript types, clean imports, and ref forwarding. React-ready with zero overhead.
Live Examples
Live Preview
Component Source Code
import { forwardRef, createElement, type ReactNode } from 'react';
type SButtonProps = JSX.IntrinsicElements['s-button'];
export type ButtonProps = Omit<SButtonProps, 'disabled' | 'loading'> & {
/** Prevents clicking or receiving focus */
disabled?: boolean;
/** Shows loading indicator and disables button */
loading?: boolean;
/** Content of the button */
children?: ReactNode;
};
/**
* Button component - triggers actions or events.
*
* @see https://shopify.dev/docs/api/app-home/polaris-web-components/actions/button
*
* @example
* <Button variant="primary">Save</Button>
* <Button variant="secondary" tone="critical">Delete</Button>
*/
export const Button = forwardRef<HTMLElement, ButtonProps>(
({ children, disabled, loading, ...props }, ref) => {
return createElement(
's-button',
{
ref,
...props,
disabled: disabled || undefined,
loading: loading || undefined,
},
children
);
}
);
Button.displayName = 'Button';What we add: Boolean prop normalization (disabled, loading) — converts React booleans to proper HTML attributes for the underlying s-button web component.
Live Preview
Component Source Code
import { forwardRef, createElement } from 'react';
type Props = JSX.IntrinsicElements['s-chip'];
export const Chip = forwardRef<HTMLElement, Props>((props, ref) => createElement('s-chip', { ref, ...props }));
Chip.displayName = 'Chip';What we add: React wrapper with full TypeScript support. Provides type-safe props, ref forwarding, and clean imports — just import and use like any React component.
Event handlers, secondaryActions slot
Boolean props, accessory slot
Typed props, clean imports, ref forwarding
Boolean props, details slot
All Primitives
Actions
| Component | Type | What we add |
|---|---|---|
| Button | Adapted | Boolean prop normalization (disabled, loading) |
| ButtonGroup | Enhanced | Auto-slotting (last → primary, others → secondary) |
| Clickable | 1:1 | Typed props, clean imports, ref forwarding |
| ClickableChip | Enhanced | Boolean props, onRemove event, graphic slot |
| Link | 1:1 | Typed props, clean imports, ref forwarding |
| Menu | Enhanced | Auto-wired trigger prop, useId integration |
Forms
| Component | Type | What we add |
|---|---|---|
| TextField | Adapted | Boolean props, accessory slot |
| EmailField | 1:1 | Use PolarisField for form library integration |
| PasswordField | 1:1 | Use PolarisField for form library integration |
| UrlField | 1:1 | Use PolarisField for form library integration |
| NumberField | 1:1 | Use PolarisField for form library integration |
| MoneyField | 1:1 | Use PolarisField for form library integration |
| SearchField | 1:1 | Use PolarisField for form library integration |
| TextArea | 1:1 | Typed props, clean imports, ref forwarding |
| DateField | Enhanced | Date object API, min/max, react-hook-form compatible |
| DatePicker | Enhanced | Date object API, min/max, single + range modes |
| ColorField | 1:1 | Typed props, clean imports, ref forwarding |
| ColorPicker | 1:1 | Typed props, clean imports, ref forwarding |
| Select | Enhanced | Value-first onChange(string), onBlur for form libs |
| Checkbox | Adapted | Boolean props, details slot |
| ChoiceList | Enhanced | Value-first onChange(string[]), JSON serialize values[], Choice sub-component |
| Switch | 1:1 | Typed props, clean imports, ref forwarding |
| DropZone | 1:1 | Typed props, clean imports, ref forwarding |
Feedback
Overlays
Layout
| Component | Type | What we add |
|---|---|---|
| Box | 1:1 | Typed props, clean imports, ref forwarding |
| Stack | 1:1 | Typed props, clean imports, ref forwarding |
| Grid | 1:1 | Typed props, clean imports, ref forwarding |
| GridItem | 1:1 | Typed props, clean imports, ref forwarding |
| Page | 1:1 | Typed props, clean imports, ref forwarding |
| Section | 1:1 | Typed props, clean imports, ref forwarding |
| Divider | 1:1 | Typed props, clean imports, ref forwarding |
| QueryContainer | 1:1 | Typed props, clean imports, ref forwarding |
Typography
| Component | Type | What we add |
|---|---|---|
| Text | 1:1 | Typed props, clean imports, ref forwarding |
| Heading | 1:1 | Typed props, clean imports, ref forwarding |
| Paragraph | 1:1 | Typed props, clean imports, ref forwarding |
| OrderedList | 1:1 | Typed props, clean imports, ref forwarding |
| UnorderedList | 1:1 | Typed props, clean imports, ref forwarding |
| ListItem | 1:1 | Typed props, clean imports, ref forwarding |
Media
Table
| Component | Type | What we add |
|---|---|---|
| Table | 1:1 | Thin wrappers for s-table-* elements |
- Not a full component library
- Not a Polaris Web Components replacement
- Not meant to be used standalone
Primitives exist to support compositions and recipes. The real value is in the composed patterns.