git:20260610.3c92643 to git:20260723.1df6c05

6 added, 5 removed. Audit A to A.

---
name: weaverse-hydrogen
description: "Build Shopify Hydrogen storefronts with Weaverse — components, schemas, loaders, theming, data fetching, React Router v7, deployment, and advanced features."
---
# Weaverse Hydrogen — Agent Skill
> Build Shopify Hydrogen storefronts with Weaverse visual page builder.
> Docs: https://docs.weaverse.io | GitHub: https://github.com/Weaverse
## Live Documentation
For the most up-to-date Weaverse documentation, use these scripts:
- `node scripts/search_weaverse_docs.mjs "<query>"` — search Weaverse docs
- `node scripts/get_weaverse_page.mjs "<page-path>"` — fetch a specific page (use paths from search results)
- Weaverse docs: https://docs.weaverse.io
**Examples:**
```bash
node scripts/search_weaverse_docs.mjs "component schema"
node scripts/search_weaverse_docs.mjs "data fetching"
node scripts/get_weaverse_page.mjs "development-guide/component-schema"
node scripts/get_weaverse_page.mjs "api-reference/weaverse-client"
```
The reference files below provide offline context but may not reflect the latest changes.
---
## What is Weaverse?
Weaverse is a visual page builder for Shopify Hydrogen. It lets merchants customize storefronts via a drag-and-drop Studio while developers build type-safe React components with schemas that define the editor UI.
**Stack:** React 19 · React Router v7 · Shopify Hydrogen · TypeScript · Tailwind CSS · Vite
---
## 1. Project Structure
```
app/
├── components/ # Reusable UI components
├── graphql/ # GraphQL queries & fragments
├── hooks/ # Custom React hooks
├── routes/ # React Router v7 route files
├── sections/ # Weaverse section components ← YOUR WORK GOES HERE
├── styles/ # Global styles + Tailwind
├── weaverse/
│ ├── components.ts # Component registry
│ ├── schema.server.ts # Theme schema (global settings)
│ └── csp.ts # Content Security Policy for Weaverse
├── entry.client.tsx
├── entry.server.tsx
└── root.tsx # Wrapped with withWeaverse(App)
server.ts # WeaverseClient initialization
vite.config.ts
react-router.config.ts
tailwind.config.js
.env
```
---
## 2. Component Anatomy
Every Weaverse component has up to 3 exports from a single file (or directory):
```tsx
// app/sections/my-section/index.tsx
// 1. Default export — React component
function MySection(props: MySectionProps) { ... }
export default MySection;
// 2. Schema export — editor configuration
export let schema = createSchema({ ... });
// 3. Loader export (optional) — server-side data fetching
export let loader = async (args: ComponentLoaderArgs<DataType>) => { ... };
```
### Minimal Example
```tsx
import { createSchema } from '@weaverse/hydrogen';
import type { HydrogenComponentProps } from '@weaverse/hydrogen';
interface BannerProps extends HydrogenComponentProps {
heading: string;
description: string;
}
function Banner({ heading, description, children, ...rest }: BannerProps) {
return (
<section {...rest} className="py-16 px-4 text-center">
<h2 className="text-3xl font-bold">{heading}</h2>
<p className="mt-4 text-lg text-gray-600">{description}</p>
{children}
</section>
);
}
export default Banner;
export let schema = createSchema({
type: 'banner',
title: 'Banner',
settings: [
{
group: 'Content',
inputs: [
{ type: 'text', name: 'heading', label: 'Heading', defaultValue: 'Hello World' },
{ type: 'textarea', name: 'description', label: 'Description', defaultValue: 'Welcome to our store.' },
],
},
],
presets: {
heading: 'Hello World',
description: 'Welcome to our store.',
},
});
```
### Key Rules
- **Spread `{...rest}`** on the root element — required for Weaverse Studio interaction.
- **Render `{children}`** if the component accepts child components (`childTypes`).
- **`forwardRef` is optional** in React 19. If using React 18, wrap with `forwardRef` and attach `ref` to root element.
- **`type` must be unique** across all components, use kebab-case (e.g., `hero-banner`).
---
## 3. Component Registration
Components must be registered in `app/weaverse/components.ts`:
```tsx
import type { HydrogenComponent } from '@weaverse/hydrogen';
// MUST use namespace imports (import * as X), NOT default imports
import * as HeroBanner from '~/sections/hero-banner';
import * as FeaturedCollection from '~/sections/featured-collection';
import * as ProductCard from '~/sections/product-card';
export let components: HydrogenComponent[] = [
HeroBanner,
FeaturedCollection,
ProductCard,
];
```
**Common mistake:** Using `import HeroBanner from ...` — this won't work. Always `import * as HeroBanner from ...`.
---
## 4. Schema with `createSchema()`
```tsx
import { createSchema } from '@weaverse/hydrogen';
export let schema = createSchema({
type: 'my-component', // Unique kebab-case identifier
title: 'My Component', // Display name in Studio
limit: 1, // Max instances per page (optional)
- enabledOn: { // Page type restrictions (optional)
- pages: ['PRODUCT', 'COLLECTION'],
- },
+ enabled: ({ page, group }) => // Dynamic insertion availability (optional)
+ ['PRODUCT', 'COLLECTION'].includes(page.type) && group === 'body',
settings: [ // Editor UI groups
{
group: 'Content',
inputs: [
{ type: 'text', name: 'heading', label: 'Heading', defaultValue: 'Title' },
{ type: 'richtext', name: 'body', label: 'Body' },
{ type: 'image', name: 'image', label: 'Image' },
{
type: 'select', name: 'layout', label: 'Layout',
configs: {
options: [
{ value: 'grid', label: 'Grid' },
{ value: 'list', label: 'List' },
],
},
defaultValue: 'grid',
},
],
},
],
childTypes: ['product-card', 'button'], // Allowed child component types
presets: { // Defaults when component is added to page
heading: 'Title',
layout: 'grid',
children: [
{ type: 'product-card' },
{ type: 'product-card' },
],
},
});
```
**`inspector` is deprecated** — always use `settings`.
- **Page types for `enabledOn`:** `INDEX`, `PRODUCT`, `ALL_PRODUCTS`, `COLLECTION`, `COLLECTION_LIST`, `PAGE`, `BLOG`, `ARTICLE`, `CUSTOM`
+ **`enabledOn` is deprecated** — move page/group checks into `enabled`. The callback is synchronous, runs in the storefront preview, and receives `{ page: { id, type, handle, locale }, group }`. Errors, Promises, and non-boolean results hide the component from new insertion without affecting existing instances. Studio currently evaluates the `body` group.
+ **Page types for `enabled`:** `INDEX`, `PRODUCT`, `ALL_PRODUCTS`, `COLLECTION`, `COLLECTION_LIST`, `PAGE`, `BLOG`, `ARTICLE`, `CUSTOM`
+
---
## 5. Input Types (Quick Reference)
| Type | Returns | Use For |
|------|---------|---------|
| `text` | `string` | Single-line text |
| `textarea` | `string` | Multi-line text |
| `richtext` | `string` (HTML) | Rich text with formatting |
| `url` | `string` | URLs/links |
| `image` | `WeaverseImage` object | Image picker from Shopify Files |
| `video` | `WeaverseVideo` object | Video picker from Shopify Files |
| `color` | `string` (#hex) | Color picker |
| `range` | `number` | Slider (requires `configs: { min, max, step }`) |
| `switch` | `boolean` | Toggle on/off |
| `select` | `string` | Dropdown (requires `configs: { options }`) |
| `toggle-group` | `string` | Button group (requires `configs: { options }`) |
| `heading` | — | Section header in settings panel (no data) |
| `datepicker` | `number` (timestamp) | Date/time picker |
| `product` | Shopify product | Product picker |
| `collection` | Shopify collection | Collection picker |
| `blog` | Shopify blog | Blog picker |
| `article` | Shopify article | Article picker |
| `metaobject` | Shopify metaobject | Metaobject picker |
| `product-list` | Shopify products[] | Multi-product picker |
| `collection-list` | Shopify collections[] | Multi-collection picker |
→ Full details: [references/04-input-settings.md](references/04-input-settings.md)
---
## 6. Data Fetching
```tsx
import type { ComponentLoaderArgs, HydrogenComponentProps } from '@weaverse/hydrogen';
type MyData = { collectionHandle: string };
export let loader = async ({ weaverse, data }: ComponentLoaderArgs<MyData>) => {
let { storefront } = weaverse;
return await storefront.query(COLLECTION_QUERY, {
variables: { handle: data.collectionHandle },
});
};
// Derive props type from loader return
type Props = HydrogenComponentProps<Awaited<ReturnType<typeof loader>>> & MyData;
function MyComponent({ loaderData, ...rest }: Props) {
let collection = loaderData?.collection;
return <section {...rest}>{collection?.title}</section>;
}
export default MyComponent;
```
**Key patterns:**
- `weaverse.storefront.query()` — Shopify Storefront API
- `weaverse.fetchWithCache(url, options)` — External APIs with caching
- `Promise.all([...])` — Parallel fetching
- `shouldRevalidate: true` on schema inputs that affect the loader
→ Full details: [references/05-data-fetching.md](references/05-data-fetching.md)
---
## 7. Styling & Theming
**Tailwind CSS** is the primary styling approach.
**Global theme settings** are defined in `app/weaverse/schema.server.ts` and applied via CSS variables:
```tsx
// app/components/GlobalStyle.tsx
import { useThemeSettings } from '@weaverse/hydrogen';
export function GlobalStyle() {
let settings = useThemeSettings();
if (!settings) return null;
return (
<style dangerouslySetInnerHTML={{ __html: `
:root {
--color-primary: ${settings.colorPrimary};
--body-base-size: ${settings.bodyBaseSize}px;
--heading-base-size: ${settings.headingBaseSize}px;
}
`}} />
);
}
```
**CVA (Class Variance Authority)** for component variants:
```tsx
import { cva } from 'class-variance-authority';
let buttonVariants = cva('inline-flex items-center rounded font-medium', {
variants: {
variant: { primary: 'bg-blue-600 text-white', secondary: 'bg-gray-200' },
size: { sm: 'h-8 px-3 text-sm', md: 'h-10 px-4', lg: 'h-12 px-6' },
},
defaultVariants: { variant: 'primary', size: 'md' },
});
```
→ Full details: [references/06-styling-theming.md](references/06-styling-theming.md)
---
## 8. Weaverse API (Key Hooks & Utilities)
| API | Purpose |
|-----|---------|
| `createSchema()` | Define component schema with Zod validation |
| `WeaverseClient` | Server-side client (initialized in `server.ts`) |
| `weaverse.loadPage({ type, handle })` | Load page data in route loaders |
| `weaverse.loadThemeSettings()` | Load global theme settings |
| `weaverse.fetchWithCache(url)` | Cached external API fetching |
| `withWeaverse(App)` | HOC wrapping root `App` in `root.tsx` |
| `useWeaverse()` | Access global Weaverse instance |
| `useThemeSettings()` | Access global theme settings |
| `useItemInstance()` | Access a specific component instance |
| `useParentInstance()` | Access parent component instance |
| `useChildInstances()` | Access child component instances |
→ Full details: [references/10-weaverse-api.md](references/10-weaverse-api.md)
---
## 9. Server Setup (server.ts)
```tsx
import { WeaverseClient } from '@weaverse/hydrogen';
import { components } from '~/weaverse/components';
import { themeSchema } from '~/weaverse/schema.server';
export async function createAppLoadContext(request, env, executionContext) {
let hydrogenContext = createHydrogenContext({ env, request, cache, waitUntil, session, /* ... */ });
return {
...hydrogenContext,
weaverse: new WeaverseClient({
...hydrogenContext,
request,
cache,
themeSchema,
components,
}),
};
}
```
---
## 10. Route Integration
```tsx
// app/routes/($locale)._index.tsx
import { WeaverseHydrogenRoot } from '@weaverse/hydrogen';
export async function loader({ context }: LoaderFunctionArgs) {
let weaverseData = await context.weaverse.loadPage({ type: 'INDEX' });
return { weaverseData };
}
export default function Homepage() {
return <WeaverseHydrogenRoot />;
}
```
For product pages:
```tsx
export async function loader({ context, params }: LoaderFunctionArgs) {
let weaverseData = await context.weaverse.loadPage({
type: 'PRODUCT',
handle: params.productHandle,
});
return { weaverseData, /* other data */ };
}
```
---
## Reference Index
For detailed information on specific topics, read these reference files:
| # | File | Topic |
|---|------|-------|
| 01 | [references/01-project-structure.md](references/01-project-structure.md) | Project structure & file anatomy |
| 02 | [references/02-creating-components.md](references/02-creating-components.md) | Component creation & registration |
- | 03 | [references/03-component-schema.md](references/03-component-schema.md) | createSchema(), settings, childTypes, presets, enabledOn |
+ | 03 | [references/03-component-schema.md](references/03-component-schema.md) | createSchema(), settings, childTypes, presets, enabled |
| 04 | [references/04-input-settings.md](references/04-input-settings.md) | All input types & configurations |
| 05 | [references/05-data-fetching.md](references/05-data-fetching.md) | Loaders, Storefront API, caching |
| 06 | [references/06-styling-theming.md](references/06-styling-theming.md) | Tailwind, theme settings, CVA, CSS variables |
| 07 | [references/07-react-router-7.md](references/07-react-router-7.md) | React Router v7 conventions |
| 08 | [references/08-hydrogen-fundamentals.md](references/08-hydrogen-fundamentals.md) | Hydrogen framework essentials |
| 09 | [references/09-deployment.md](references/09-deployment.md) | Oxygen, Docker, env vars |
| 10 | [references/10-weaverse-api.md](references/10-weaverse-api.md) | All hooks & WeaverseClient API |
| 11 | [references/11-advanced-features.md](references/11-advanced-features.md) | Localization, data connectors, CSP |
| 12 | [references/12-pilot-theme.md](references/12-pilot-theme.md) | Pilot theme patterns & conventions |
| 13 | [references/13-migration-v5.md](references/13-migration-v5.md) | Remix → React Router v7 migration |
| 14 | [references/14-sdk-caching-and-diagnostics.md](references/14-sdk-caching-and-diagnostics.md) | SDK 5.15.x caching, Builder diagnostics headers, nested multi-instance pages, client upgrades |
## Examples
| File | Shows |
|------|-------|
| [examples/hero-banner.tsx](examples/hero-banner.tsx) | Complete section with schema, settings groups, childTypes, presets |
| [examples/featured-collection.tsx](examples/featured-collection.tsx) | Section with loader, Storefront API query |
| [examples/product-card.tsx](examples/product-card.tsx) | Child component example |
| [examples/components-registry.ts](examples/components-registry.ts) | Registration pattern |