Weaverse Hydrogen — Agent Skill

SkillCloud & infra

Build Shopify Hydrogen storefronts with Weaverse — components, schemas, loaders, theming, data fetching, React Router v7, deployment, and advanced features.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Weaverse Hydrogen — Agent Skill skill

What this skill tells your AI

The instructions your AI receives, as published by weaverse/shopify-hydrogen-skills in skills/weaverse-hydrogen/SKILL.md and read by ahel’s review.

Build Shopify Hydrogen storefronts with Weaverse visual page builder. Docs: https://docs.weaverse.io | GitHub: https://github.com/Weaverse

Live Documentation

Run these from this skill's own folder. The helpers ship inside the sibling shopify-hydrogen skill, so ../shopify-hydrogen/scripts/ exists whenever the whole pack is installed.

If you installed this skill on its own, that folder is absent and the commands below fail with MODULE_NOT_FOUND. Add the helpers once:

npx skills add Weaverse/shopify-hydrogen-skills --skill shopify-hydrogen

The references/ files in this skill remain a usable offline fallback if you would rather not install it.

For the most up-to-date Weaverse documentation, use these scripts:

  • node ../shopify-hydrogen/scripts/search_weaverse_docs.mjs "<query>" — search Weaverse docs
  • node ../shopify-hydrogen/scripts/get_weaverse_page.mjs "<page-path>" — fetch a specific page (use paths from search results)
  • Weaverse docs: https://docs.weaverse.io

Examples:

node ../shopify-hydrogen/scripts/search_weaverse_docs.mjs "component schema"
node ../shopify-hydrogen/scripts/search_weaverse_docs.mjs "data fetching"
node ../shopify-hydrogen/scripts/get_weaverse_page.mjs "development-guide/component-schema"
node ../shopify-hydrogen/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):

// 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

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:

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()

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)

TypeReturnsUse For
textstringSingle-line text
textareastringMulti-line text
richtextstring (HTML)Rich text with formatting
urlstringURLs/links
imageWeaverseImage objectImage picker from Shopify Files
videoWeaverseVideo objectVideo picker from Shopify Files
colorstring (#hex)Color picker
rangenumberSlider (requires configs: { min, max, step })
switchbooleanToggle on/off
selectstringDropdown (requires configs: { options })
toggle-groupstringButton group (requires configs: { options })
headingSection header in settings panel (no data)
datepickernumber (timestamp)Date/time picker
productShopify productProduct picker
collectionShopify collectionCollection picker
blogShopify blogBlog picker
articleShopify articleArticle picker
metaobjectShopify metaobjectMetaobject picker
product-listShopify products[]Multi-product picker
collection-listShopify collections[]Multi-collection picker

→ Full details: references/04-input-settings.md


6. Data Fetching

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


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:

// 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:

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


8. Weaverse API (Key Hooks & Utilities)

APIPurpose
createSchema()Define component schema with Zod validation
WeaverseClientServer-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


9. Server Setup (server.ts)

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

// 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:

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:

#FileTopic
01references/01-project-structure.mdProject structure & file anatomy
02references/02-creating-components.mdComponent creation & registration
03references/03-component-schema.mdcreateSchema(), settings, childTypes, presets, enabled
04references/04-input-settings.mdAll input types & configurations
05references/05-data-fetching.mdLoaders, Storefront API, caching
06references/06-styling-theming.mdTailwind, theme settings, CVA, CSS variables
07references/07-react-router-7.mdReact Router v7 conventions
08references/08-hydrogen-fundamentals.mdHydrogen framework essentials
09references/09-deployment.mdOxygen, Docker, env vars
10references/10-weaverse-api.mdAll hooks & WeaverseClient API
11references/11-advanced-features.mdLocalization, data connectors, CSP
12references/12-pilot-theme.mdPilot theme patterns & conventions
13references/13-migration-v5.mdRemix → React Router v7 migration
14references/14-sdk-caching-and-diagnostics.mdSDK 5.15.x caching, Builder diagnostics headers, nested multi-instance pages, client upgrades

Examples

FileShows
examples/hero-banner.tsxComplete section with schema, settings groups, childTypes, presets
examples/featured-collection.tsxSection with loader, Storefront API query
examples/product-card.tsxChild component example
examples/components-registry.tsRegistration pattern

Signals

GitHub stars
87
Forks
26
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
weaverse-hydrogen
Source
github.com/weaverse/shopify-hydrogen-skills