weaverse-hydrogen

$npx mdskill add Weaverse/shopify-hydrogen-skills/weaverse-hydrogen

Build Shopify Hydrogen storefronts with Weaverse visual page builder.

  • Create and manage components, schemas, loaders, and theming for Hydrogen.
  • Depends on Shopify Hydrogen, React Router v7, Weaverse Studio, and docs API.
  • Uses documentation scripts and reference files to guide component and data logic.
  • Outputs code, schemas, and deployment instructions for the developer.

SKILL.md

.github/skills/weaverse-hydrogenView on GitHub ↗
---
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)
  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`.

**`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, 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 |

More from Weaverse/shopify-hydrogen-skills

SkillDescription
cloning-websites-to-weaverseUse when recreating a reference website or brand hub in this Hydrogen plus Weaverse repo, especially when deciding whether to reuse sections, add global styles, update theme schema, or resolve conflicts between the live site and project brand guidelines.
figma-to-weaverseUse when recreating a Figma design as Hydrogen + Weaverse pages in this repo — turning a Figma file, frame, or flow into reusable Weaverse sections. Triggers on a figma.com URL, "build this design", "implement this Figma", or "create the storefront from the design". The Figma counterpart of cloning-websites-to-weaverse.
generating-weaverse-project-jsonUse when generating Weaverse project export JSON for import into the Weaverse editor. Triggers on requests to create, build, or produce a Weaverse project JSON file from a site migration, design spec, page layout description, or existing export. Also use when converting section plans into importable project and pages data.
hydrogen-analytics-trackingEnd-to-end analytics & conversion tracking on Shopify Hydrogen — GTM, GA4 (browser + Measurement Protocol), Meta Pixel + CAPI, Google Ads, consent mode, CSP, Oxygen full-page cache. Real-world patterns from production deployments.
hydrogen-cookbooksStep-by-step implementation guides for building features in a Shopify Hydrogen storefront — bundles, combined listings, customer accounts, 3D models, performance, variant media, and Weaverse integration.
hydrogen-upgradesStep-by-step guides for upgrading Shopify Hydrogen between versions — breaking changes, code diffs, and migration steps for each release.
setup-weaverse-projectSet up, create, scaffold, or clone a new Weaverse Hydrogen storefront locally from a Weaverse theme. Use CLI-first setup, boot a live demo-store preview before asking for Shopify credentials, then make it the merchant's own with env, GitHub, and Builder preview connection.
shopify-hydrogenCore Shopify Hydrogen APIs — createHydrogenContext, cart handler, CartForm, caching strategies, pagination, SEO, variant selection, analytics, and CSP.
theme-updateSafely update a Weaverse Pilot theme to the latest version — detects current version, fetches release diffs, plans changes category-by-category, preserves customizations, verifies build.
weaverse-content-apiUse when reading or updating live Weaverse content programmatically — pulling projects/pages/theme settings, bulk-editing page content, pushing AI-generated copy, deleting pages, or uploading media to Shopify for use in Weaverse. Triggers on requests to update a Weaverse project via API, push content to a live project, run bulk content edits, or upload images/assets to Shopify from automation.