.dev
Storefront templates

Create a template

Create a Helium storefront theme, edit a merchant-controlled block, preview it on your store and publish a release.

This walkthrough uses the Helium starter. For an existing Lithium theme, begin with the migration guide. You need the Feeef CLI and a store you own; a private storefront repository is not required.

1. Select the API and sign in

npm install -g @feeef.dev/cli
feeef signin

The CLI defaults to the alpha API. For a production store, select its API before signing in:

feeef config set apiUrl https://api.feeef.org/v1
feeef signin

A token belongs to the API that issued it. The CLI and storefront must read the same API for draft preview to work.

2. Create and inspect the project

feeef template init my-theme --helium --store my-shop
cd my-theme
npm run check
npm run build

--store accepts a slug or ID and writes .feeefrc. Use feeef use to link or switch later. The folder must be empty and its name must match [a-z0-9-_]+.

OutputMeaning
dist/data.jsonThe TemplateData document, with runtime: "helium" and schemaVersion: 2
dist/schema.jsonYour editor schema merged with platform built-ins
dist/locales/*.jsonCompiled translation files

Read docs/24-HELIUM-RUNTIME.md in the project. The starter includes nine standard pages; keep schema.ts, the manifest and page folders aligned. feeef template add page updates the manifest, so add the matching editor schema entry when creating a page.

Other starts are --git <url> and --from <templateId> for a free public template. --blank remains the Lithium starter. Paid templates are purchased and installed through the merchant app rather than unpacked into a new project.

3. Add an editable block

feeef template add component home delivery-note --title "Delivery note"

Edit the generated pages/home/components/delivery-note.tsx:

export const meta = {
  type: "custom",
  title: "Delivery note",
  order: 20,
  hydrate: "never",
  propsSchema: {
    message: { type: "string", name: "Message" },
  },
  props: { message: "Delivery to your door" },
} as const;

function App() {
  return <p className="delivery-note">{props.message}</p>;
}

propsSchema describes the inspector; props supplies editable defaults. This block only prints text, so it can stay as server HTML. Keep interactive components hydrated; see the hydration guide. For multilingual copy, add locale keys and use t() rather than embedding fixed shopper-facing strings throughout a theme.

Use a component folder only for slots or children. Avoid a flat file and a folder with the same component ID. Reuse shared blocks with a placement such as:

{ "$ref": "shared.footer", "instanceId": "footer_home", "props": {} }

The build resolves that placement. A library/components/ file is an insertable block; it appears on a page when the merchant places it.

4. Preview and verify

npm run check
npm run build
npm run check:perf
npm test
npm run dev

The hosted draft opens at https://{slug}.h.feeef.store/?preview=…. Walk home → product → cart → checkout and test touch, keyboard, pickers, totals and translations. Preview uses real products and prices; use a development store for checkout testing. Local smoke checks catch render errors but do not reproduce hosted QuickJS or browser hydration.

Customers continue to see the installed document. Leave preview through its banner or /?preview=0; stopping the CLI clears the draft. If your edits do not appear, check the API selection and preview cookie first.

5. Publish a release

# Upload a private release and install it on the linked store
npm run publish -- --apply

# Or publish a free public release and install it
feeef template publish --public --apply

Publishing writes listing data, components, locales and an immutable release. Applying it changes the live install. Without --apply, publishing can leave the existing live install in place; see Develop and publish for prompt and version behavior.

Keep dist/ as build output. Edit the source package, preview, then release. Review hosting and domain routing separately when moving a store from another runtime.

On this page