# Build a theme section (/themes/build-a-section)

You add a **USP strip** to a theme: one line of reassurance such as "Free delivery over 50", with an
alignment choice, text merchants edit in place, and the Customizer's spacing, background, typography and
visibility controls. Then you place it on the home page and publish it.

Prompt for an AI coding tool:

```text
Follow https://developers.poltura.com/themes/build-a-section.md and keep to the theme rules in https://developers.poltura.com/ai/rules/AGENTS.md.
Write a Poltura theme section in src/sections/usp-strip.tsx with defineSection from @poltura/theme-sdk/elements.
It has a text setting with a default, an alignment select (left, center), EditableText for the text, and the style list spacing, background, typography and visibility.
Spread attrs onto the one root element and merge classes with cn from @poltura/theme-sdk/ui.
Import only from @poltura/theme-sdk modules, react and the theme's own files. Do not use em dashes in default copy.
```

## Before you start [#before-you-start]

- A Poltura store where you can edit the online store's theme.
- Nothing to install. Theme code is written in the theme code editor, which runs in the browser and checks your
  code on every save.

### Open the theme code editor [#open-the-theme-code-editor]

In the admin, open **Online store → Themes** and choose **Edit in code editor** on the theme you want to change.
The Customizer's top bar links to the editor too.

The editor works on the theme's **draft**. Saving never changes the live storefront. Publishing is a separate
step at the end.

### Create the section file [#create-the-section-file]

Open the command palette (Cmd+Shift+P on a Mac, Ctrl+Shift+P elsewhere)
and run **Theme: New Section…**. Name it `usp-strip`. The editor writes `src/sections/usp-strip.tsx` with a
working starter: a heading, a text, a slot for child blocks and the standard style list.

There is no registry to update. The theme compiler finds every `defineSection` in `src/sections/` on save.

### Write the section [#write-the-section]

Replace the file's content with this:

```tsx title="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',
  description: 'One short line of reassurance',
  icon: 'section',
  category: 'marketing',
  settings: {
    text: field.text({ label: 'Text', default: 'Free delivery over 50' }),
    alignment: field.select({
      label: 'Alignment',
      options: [
        { value: 'left', label: 'Left' },
        { value: 'center', label: 'Center' },
      ],
      default: 'center',
    }),
  },
  style: ['spacing', 'background', 'typography', 'visibility'],
  component: ({ settings, attrs }) => (
    <section {...attrs} className={cn(attrs.className, 'py-6')}>
      <div className='theme-container'>
        <EditableText
          setting='text'
          as='p'
          className={cn('text-foreground', settings.alignment === 'center' && 'text-center')}
        />
      </div>
    </section>
  ),
});
```

What each part does:

- **`type`** is the section's permanent key in the theme's page files. Keep it once merchants use the section.
  To rename it later, list the old key in `renamedFrom`.
- **`label`, `description`, `icon` and `category`** are what merchants see in the Customizer's section picker.
  `marketing` lists it under Marketing.
- **`settings`** become the fields of the section's inspector. Each `field.*` builder has a label and a default,
  and the component receives the values already typed as `settings`.
- **`style`** lists the style controls merchants get. The platform turns their choices into classes and
  attributes on `attrs`.
- **`attrs`** must be spread onto exactly one root element, with `cn(attrs.className, ...)` to merge your own
  classes. Without it, the style controls do nothing.
- **`EditableText`** renders the `text` setting and lets merchants edit it in place on the canvas.

Every field and style control is listed in [Sections, blocks and element styles](/themes/elements).

### Save and read the check [#save-and-read-the-check]

Save the file. The editor runs the theme check on every save and lists anything wrong in the **Problems**
panel, with the line and column. The section above passes. These are the mistakes it catches most often, with
the message you get (the last one is shortened):

```text
src/sections/usp-strip.tsx(26,19): [usage] reads setting "txt" no element definition declares for usp-strip (declared: text, alignment)
src/sections/usp-strip.tsx(18,7): [types] Type '"middle"' is not assignable to type '"center" | "left" | undefined'.
src/sections/usp-strip.tsx(5,3): [elements] type "UspStrip" must be kebab-case starting with a letter (bad-definition)
src/sections/usp-strip.tsx(2,21): [import] Theme file src/sections/usp-strip.tsx imports "lodash", which is outside the theme surface.
```

The full import message lists what a theme may import: `@poltura/theme-sdk/*`, the theme's own files, React,
and a fixed set of libraries such as `@radix-ui/*`, `lucide-react`, `motion` and `clsx`.

Fix them until the panel is empty.

### Place it in the Customizer [#place-it-in-the-customizer]

In the admin, choose **Customize** on the theme. On the home page choose **Add section**, find **USP strip**
under **Marketing** and add it. You see:

- "Free delivery over 50" on the canvas. Click it and type to change it.
- **Alignment** with Left and Center in the section's settings.
- Spacing, Background, Typography and Visibility in its style controls.

The Customizer writes the placement into the draft's `pages/home.json`. Your section's code stays in
`src/sections/usp-strip.tsx`.

### Publish [#publish]

Choose **Publish** in the Customizer (or **Publish** in the code editor's status bar). The draft's code and
layout go live together. Until then, shoppers see the previous version.


## Go further [#go-further]

- **Child blocks:** let merchants add blocks inside the section with `blocks: { accepts: [...] }` and render them
  with `<Slot />`. The starter file the editor wrote shows the pattern.
- **Limit where it appears:** `templates: ['home', 'page']` keeps it off product and cart pages.
- **Translate the picker:** `i18n: { hu: { label: '...' } }` on the section and on each field.
- **Draw store data:** read products with the hooks of [`@poltura/theme-sdk/data`](/themes/sdk/reference/data)
  and draw prices with the parts of [`@poltura/theme-sdk/price`](/themes/sdk/reference/price).

The [USP strip example](/apps/examples) is this section with the first three steps done: `usp-item` child
blocks, a starting preset, three templates and Hungarian labels.

## Next [#next]

- [Sections, blocks and element styles](/themes/elements): defineSection, defineBlock, fields and styles.
- [Server rendering](/themes/server-rendering): Rules for code that renders on the server.
- [Theme SDK reference](/themes/sdk): 25 typed modules, from cart to ui.
