Developers
Start building
Themes/How themes work

How themes work

A Poltura theme is code. You edit it in the browser code editor, write sections and blocks against the typed theme SDK, and check it before you publish.

On this page
SectionFree delivery strip
Section added

A theme is a tree of TSX components and JSON files. Sections and blocks are React components declared with defineSection and defineBlock. Page layouts, setting values and texts are JSON files beside them. Merchants arrange sections in the Customizer; you write what the Customizer cannot do.

Open the code editor

Every store can run its own theme code. In the admin, open Online store → Themes and choose Edit in code editor on a theme. The Customizer's top bar links to the editor too.

It is a code editor in the browser, with TypeScript completions from the theme SDK, Tailwind hints, format on save, the Theme: New Section… command, a Changes panel and a timeline of earlier saves. Saves go to the theme's draft. Publishing is a separate step, so the live storefront does not change while you work.

A theme imports Poltura APIs from @poltura/theme-sdk/<module>. It may also import its own files, React and a fixed set of libraries (for example @radix-ui/*, lucide-react, motion, clsx and zod). When the check refuses an import, its message lists every allowed package.

The theme tree

theme.json                          name, schema_version, engine
settings/schema.json                generated from src/settings.ts on every save
settings/values.json                setting values
settings/presets.json               style presets the merchant switches between
pages/<template>.json               section layout per template (home, product, ...)
pages/custom/<name>.json            layouts of the merchant's custom pages
layout/header.json, footer.json     header and footer section groups
emails/<slug>.json                  email content
texts/<language>.json               the theme's own UI texts, one file per language
assets/                             images, fonts and icons the theme ships
og/<kind>.tsx                       share image templates (optional)
src/settings.ts                     the theme settings panel, written with field.*
src/sections/, src/blocks/          section and block types, one per file
src/layout/                         optional chrome in code, such as chat.tsx
src/templates/                      optional templates in code, such as pages/landing.tsx
src/components/, src/styles/        shared components and CSS
src/preview-scenarios.ts            sample data states for the Customizer

Write a section

Each file under src/sections/ or src/blocks/ declares its type once. The compiler reads the declarations without running them and builds the Customizer's picker, the editor's layout schema and the publish checks from them. There is no registry file.

src/sections/usp-strip.tsx
import { EditableText, defineSection, field } from '@poltura/theme-sdk/elements';
import { cn } from '@poltura/theme-sdk/ui';

export const uspStrip = defineSection({
  type: 'usp-strip',
  label: 'USP strip',
  icon: 'section',
  category: 'marketing',
  settings: { text: field.text({ label: 'Text', default: 'Free delivery over 50' }) },
  style: ['spacing', 'background', 'typography'],
  component: ({ attrs }) => (
    <section {...attrs} className={cn(attrs.className, 'py-6')}>
      <EditableText setting='text' as='p' className='theme-container text-center' />
    </section>
  ),
});

The component spreads attrs onto its one root element. That is how the merchant's style choices reach it. The Build a theme section tutorial walks through the whole flow, from the editor to publishing. Sections, blocks and element styles covers settings, blocks and style capabilities.

Style presets

settings/presets.json lists up to eight named looks of the theme. Each preset has an id, a label, one to five #rgb or #rrggbb swatches for the picker, and a partial set of settings/values.json values:

settings/presets.json
{
  "$schema": "../.schemas/presets.schema.json",
  "presets": [
    {
      "id": "bright",
      "label": "Bright",
      "label_i18n": { "hu": "Élénk" },
      "swatches": ["#ff3d7f", "#111111", "#fafafa"],
      "values": { "colors.primary": "#ff3d7f", "colors_dark.primary": "#ff8fb1", "radius": "0" }
    }
  ]
}

Switching to a preset changes the draft's settings only. Every look setting takes the preset's value, or else its default (dark_default for a dark twin) from settings/schema.json, so nothing of the previous preset survives. Content settings and every page, layout, text and email stay as they are. Ids use a-z, 0-9 and -, and default is reserved for the shipped look.

A setting's type decides whether it is look or content. Colours, gradients, fonts, selects, radios, numbers, ranges and checkboxes are look. Text, images, links and the rest are content. A setting overrides this with "content": true (a "Show the cookie bar" checkbox is the merchant's decision, not the theme's look) or "content": false (a text field holding a CSS length).

A preset value must name a look setting of settings/schema.json and fit its type. Once a theme ships presets, every look setting needs a default. Saving, installing, publishing and building the theme all refuse a presets file that breaks these rules.

Check before you publish

The code editor runs the theme check on every save and lists its findings in the Problems panel, each with a line and column. It checks layout files, sections, settings, imports and types.

The same check runs as poltura theme check <dir> on a theme directory. --types <pack> points it at the theme SDK's type pack, and --json prints one machine-readable line. The same command line can also pull a theme into a folder, push your edits to a draft, preview, publish and roll back: see Theme commands. Not on npm yet

Next

Last updated