> ## Documentation Index
> Fetch the complete documentation index at: https://docs.senderz.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Popup blocks

> Every block the popup builder offers, its settings, the spacing model, shared styles, step layouts and the teaser.

A popup is built from **blocks**. You add them from the **Add content** panel, the first icon on the builder's left rail, and you edit one by clicking it on the canvas. Block settings only ever appear that way. The rail's other panels are popup-wide, so nothing about an individual block lives there.

This page is the reference for what each block does and what you can set on it. For who sees the popup and when, see [Popups and forms](/en/messaging/popups).

## The palette

Add content lists blocks in three groups.

<Tabs>
  <Tab title="Elements">
    | Block                | What it is                                                  |
    | -------------------- | ----------------------------------------------------------- |
    | **Text**             | Rich text. Headings, body copy and anything in between.     |
    | **Image**            | A picture, with fit, anchor and an optional click action.   |
    | **Button**           | The control that submits the step's form.                   |
    | **Coupon code**      | A discount code from your Coupon Library.                   |
    | **Spin wheel**       | A prize wheel game.                                         |
    | **Scratch card**     | A scratch-to-reveal game.                                   |
    | **Mystery box**      | Pick-a-box, with no game-of-chance element.                 |
    | **Education / Info** | A title, body copy, an optional image and a dismiss button. |
    | **Countdown timer**  | A live countdown.                                           |
    | **Divider**          | A horizontal rule.                                          |
  </Tab>

  <Tab title="Input fields">
    | Block                   | What it is                                                 |
    | ----------------------- | ---------------------------------------------------------- |
    | **Form**                | The group that validates and submits everything inside it. |
    | **Email field**         | Collects the email address.                                |
    | **Phone field**         | Collects the phone number, with a country dialling code.   |
    | **Name field**          | Collects the first name.                                   |
    | **Birthday**            | A date field preset with a day/month/year mask.            |
    | **Custom field**        | Any other contact property.                                |
    | **Quiz / Question**     | A question with answers that can branch and segment.       |
    | **Consent**             | One opt-in checkbox for one channel.                       |
    | **Push subscribe**      | A browser notification opt-in.                             |
    | **One-time code input** | A six-digit code field.                                    |
  </Tab>

  <Tab title="Advanced">
    | Block                | What it is                                          |
    | -------------------- | --------------------------------------------------- |
    | **Custom HTML / JS** | Your own markup and script, with a small popup API. |
  </Tab>
</Tabs>

### Blocks you cannot add yet

Two palette entries are greyed out rather than hidden, so you can see why they are unavailable:

* **Phone field** needs a usable SMS channel. Turn on SMS and get a branded Sender name approved first. See [Sender IDs](/en/deliverability/sender-ids).
* **One-time code input** needs OTP verification, which is planned after v1.

**Form** greys out once the step already has one. A step renders exactly one form, so a second one would save and then never appear.

<Note>
  A greyed-out block still tells you its reason when you hover it. Nothing is
  removed from the palette silently.
</Note>

## Blocks that render but can no longer be added

Seven block types were retired from the palette. They still render, still open their settings and can still be deleted, so an older popup keeps working exactly as it did. You just cannot add a new one.

| Retired block    | Use instead                                    |
| ---------------- | ---------------------------------------------- |
| Heading          | **Text**                                       |
| Subheading       | **Text**                                       |
| Inline text      | **Text**                                       |
| Plain button     | **Button**, or a container with a click action |
| Icon             | **Image**, or a container with a click action  |
| Social proof     | **Text**                                       |
| Micro-commitment | **Quiz / Question** with two answers           |

If you open a popup built earlier and find a block you cannot re-add after deleting it, this is why. Replace it before you delete it.

## Containers

Every new step is wrapped in one **container**, created for you, and so is every step in a gallery starter. It is the step's layout frame. Clicking it opens a **Layout** section:

| Setting          | Options                                                 |
| ---------------- | ------------------------------------------------------- |
| Direction        | Vertical or Horizontal, with a **Reverse order** switch |
| Horizontal align | Start, Center, End, Stretch, Space between              |
| Vertical align   | Start, Center, End, Stretch, Space between              |
| Spacing          | The gap between the blocks inside                       |
| Wrapping         | No wrap, or Wrap onto a second line                     |
| Overflow         | Visible, or Hidden to clip what sticks out              |

Align values are written in reading order, so **Start** is the right edge in Hebrew and the left edge in English. The two align controls swap which axis they act on when you flip Direction, and the panel relabels them so they stay honest.

**Randomize child order** shuffles the container's blocks for every visitor. The builder canvas deliberately keeps your authored order so it stays editable, and shows a badge instead.

A container can also carry a click action, which makes the whole area clickable.

<Warning>
  **Nesting is one level.** A container cannot hold another container, and a
  form cannot hold a form. A container holds at most **20** blocks.
</Warning>

## The form group

The form is the group that validates and submits. Anything inside it is checked before submission and sent; anything outside it is skipped.

A form holds input fields, the consent checkbox, the submit button, push subscribe, and presentational blocks around them (text, image, divider). Games and quizzes sit outside it, because each of those is its own interactive block and would fight the form for the step.

<Warning>
  A field placed outside the form gets an **Outside the form** badge on the
  canvas and a warning: it will not be submitted. Move it inside the form.
</Warning>

## Text

Text is rich text. The settings panel accepts **HTML and expressions**.

Expressions are written in double curly braces and are replaced with live values just before the block is drawn:

| Expression               | Resolves to                                 |
| ------------------------ | ------------------------------------------- |
| `{{email}}`              | The email the visitor typed                 |
| `{{phone}}` or `{{sms}}` | The phone number the visitor typed          |
| `{{profile.firstName}}`  | A property already known about this profile |
| `{{variables.myName}}`   | A variable your custom code set             |
| `{{fieldName}}`          | The value of another field on this popup    |

An expression that resolves to nothing renders as an empty string, never as the raw token.

## Image

| Setting             | What it does                                                           |
| ------------------- | ---------------------------------------------------------------------- |
| Image               | Pick from your media library, upload, generate with AI, or paste a URL |
| Image alt / label   | The description read out by screen readers                             |
| Fit                 | Cover or Contain                                                       |
| Position and anchor | A nine-point grid, plus exact X and Y percentages                      |
| Shadow              | A drop shadow behind the image                                         |
| Action when clicked | Any of the click actions below                                         |

## Divider

A divider has no settings. Style it with the block background, padding and radius controls.

## Input fields

Every input field shares one set of options.

| Setting                    | Notes                                                    |
| -------------------------- | -------------------------------------------------------- |
| Placeholder                | The grey hint inside the box                             |
| Accessibility label        | Read out by screen readers                               |
| Show the label in the form | Off keeps the label for screen readers only              |
| Required                   | Blocks submission when empty                             |
| Message when empty         | Shown when a required field is left blank                |
| Message when invalid       | Shown when a value is present but fails its format check |
| Profile property           | Where the answer is saved                                |

**Email**, **Phone** and **Name** write to a fixed property. Their mapping is shown but not editable, because the subscribe request is keyed on it and remapping would drop the value with no error.

Every other field lets you pick any non-computed contact property, or **Do not save this answer**, which collects nothing. Values land on the right contact column when the property has one, and in the contact's custom properties otherwise. See [Contacts](/en/audience/contacts).

### Phone field

Adds a **Country** setting: the dialling code the visitor starts on. They can pick another one.

### Custom field

Adds four more settings:

| Setting     | What it does                                                                                 |
| ----------- | -------------------------------------------------------------------------------------------- |
| Input type  | Text, Email, Phone, Number, Date or URL                                                      |
| Multi-line  | Renders a text area. Masks and the age gate do not apply                                     |
| Input mask  | `D`, `M`, `Y`, `9`, `0` and `#` are digit slots. Everything else is typed in for the visitor |
| Minimum age | Blocks submission below this age, in whole years                                             |

The age gate needs a date mask to read the value from. When you set a minimum age, a **Message below the age** field appears.

**Birthday** in the palette is this same field, pre-set with a `DD/MM/YYYY` mask and a date-of-birth mapping. Add a minimum age to it to build an age gate.

### Quiz / Question

| Setting                 | What it does                                                      |
| ----------------------- | ----------------------------------------------------------------- |
| Question                | The prompt                                                        |
| Answers                 | Label and value per answer, reorderable                           |
| Add picker to segment   | Puts anyone who picks this answer into a segment                  |
| Submit the answer, then | Per-answer actions, including going to a specific step            |
| Profile property name   | The chosen answer's value is saved on the profile under this name |
| An answer is required   | Plus its validation message                                       |
| Layout style            | Buttons, Checkboxes, Radio buttons or Dropdown                    |
| Option layout           | Vertical or Horizontal                                            |
| Alignment               | Start, Center or End                                              |

Per-answer segments are what make a welcome flow branch on what the visitor picked. See [Segments](/en/audience/segments).

### Push subscribe

A button that asks the browser for notification permission. The label is the only setting.

It needs a service worker on your own storefront domain, so it works on **Shopify** and on **WordPress and WooCommerce**. On Konimbo there is no same-origin path for it and the block does not render. See [Push](/en/channels/push).

## The consent block, and what it changes

A consent block is one checkbox for one channel: **Email**, **SMS** or **WhatsApp**. Its settings are the channel, the checkbox text, whether ticking it is required, and an optional profile property to record the answer on.

<Warning>
  **A consent box is never ticked in advance and this is not configurable.**
  Israeli law needs an explicit opt-in. See
  [Israeli compliance](/en/compliance/israel).
</Warning>

The block changes how opt-in is decided for the whole popup:

<CardGroup cols={2}>
  <Card title="No consent block on the step" icon="check">
    Submitting the form is the opt-in. A visitor who gives an email is
    subscribed to email; one who gives a phone is subscribed to SMS.
  </Card>

  <Card title="A consent block for that channel" icon="square-check">
    The checkbox decides. Leaving it unticked subscribes nothing on that
    channel, even though the address was collected.
  </Card>
</CardGroup>

The two channels are independent. An email consent box left unticked does not affect the phone number, and vice versa.

**WhatsApp is opt-in only.** It is never inferred from a phone number and never rides along with the SMS opt-in. It needs WhatsApp set up in your workspace, the popup's own WhatsApp toggle on, and the visitor ticking the box with a phone number present.

See [Consent](/en/audience/consent) for what each state means downstream.

## The submit button

The **Button** block submits its step's form. A button with no action configured still submits, so nothing needs setting for the basic case.

| Setting                | What it does                                                                  |
| ---------------------- | ----------------------------------------------------------------------------- |
| Button label           | The text on the button                                                        |
| Left icon / Right icon | None, Arrow, Chevron, Check or Lock                                           |
| List to Submit         | The list every submitting profile joins                                       |
| Submit hidden fields   | A property and a fixed value saved on every submission, with no visible field |
| When form is submitted | An ordered list of actions that run after a successful submit                 |

<Warning>
  **Joining a list is not consent.** What you may actually send someone is
  still decided by their email and SMS consent, at send time. Filing a profile
  into a list does not grant permission to mail them.
</Warning>

A list you picked earlier that has since been archived or deleted stays visible as a disabled row rather than silently resetting your choice.

## Click actions

Thirteen actions can be attached to a block. They appear as **Action when clicked** on an image or a container, and as the ordered **When form is submitted** list on the submit button.

| Action                               | What it does                                                  |
| ------------------------------------ | ------------------------------------------------------------- |
| Go to step                           | Jumps to the step you choose                                  |
| Next step                            | Moves to the following step                                   |
| Minimize to floating button          | Closes the popup and shows its teaser                         |
| Close popup                          | Closes it completely                                          |
| Dismiss (keep teaser)                | Closes it and leaves the teaser showing, if one is enabled    |
| Open URL                             | Only http, https, mailto, tel and same-site paths are allowed |
| Add item(s) to cart                  | Adds the listed variants before the next action runs          |
| Modify selling plan                  | Updates the selected variant and selling plan                 |
| Set user property                    | Writes a value onto the submitted profile                     |
| Branch if user is already subscribed | After submission, subscribed visitors go to a different step  |
| Track click                          | Records a click under your analytics label                    |
| Time delay                           | Waits a number of milliseconds before the next action runs    |
| Custom code                          | Runs your JavaScript on the storefront                        |

Actions in the after-submit list run in order, top to bottom, and you can reorder them.

## The coupon reward block

The coupon block hands the visitor a discount code. **It links a real coupon from your Coupon Library. You do not type a code into it**, because a typed string is not a discount in your store and would fail at checkout.

| Setting           | What it does                                                      |
| ----------------- | ----------------------------------------------------------------- |
| Reward            | Picks a coupon, or creates one without leaving the builder        |
| Reveal text       | The placeholder shown in the code box before the code arrives     |
| Apply to checkout | Adds the code to the cart automatically when this step is reached |

**Apply to checkout** works on Shopify and WooCommerce only.

### Shared code or unique per subscriber

The picker labels each coupon:

<CardGroup cols={2}>
  <Card title="Shared code" icon="ticket">
    One code every subscriber gets. It can sit on **any** step, including the
    very first one.
  </Card>

  <Card title="Unique per subscriber" icon="fingerprint">
    A different code per person, drawn from a finite pool of real store
    discounts. It may **only** sit on a step the visitor reaches after
    subscribing.
  </Card>
</CardGroup>

<Warning>
  A unique-code reward is restricted to a **reward**, **message** or **thank
  you** step. Those are the steps that come after a submission. Put one on an
  earlier step and the builder blocks it with a message telling you to move it
  or pick a shared code, and the save is refused.

  The reason is cost. Each unique code is a real discount created in your
  store, and the pool is finite. Revealing one on an opening step would burn a
  code on every popup **view** rather than on every subscriber, and a popup
  seen a thousand times would drain a thousand codes to gain a handful of
  signups.
</Warning>

### Pool warnings

When you link a unique-per-subscriber coupon the block shows the pool state inline:

* **Codes left** while the pool is healthy.
* An amber warning as it runs low.
* A red warning when it is empty: subscribers see no code until you add more.

See [The unique-code pool](/en/messaging/coupons#the-unique-code-pool).

### Legacy typed codes

A block built before rewards were linked still shows its typed string, with a notice telling you to pick a real reward so the discount exists in your store. Nothing breaks in the meantime, but the code is not verified against your store.

## Countdown timer

Four timer types, each answering a different question:

<AccordionGroup>
  <Accordion title="Duration">
    Counts down from a fixed length **every time the popup opens**. Set days,
    hours, minutes and seconds. Good for urgency that resets.
  </Accordion>

  <Accordion title="End date">
    Counts down to **one moment in time, the same for every visitor**. Set the
    date and time, plus the time zone it is read in.
  </Accordion>

  <Accordion title="End of period">
    Counts down to the next **Hour**, **Day**, **Week** or **Month** boundary
    in the selected time zone. Weeks end on Sunday.
  </Accordion>

  <Accordion title="Evergreen">
    Starts when a visitor **first sees the popup** and follows them on that
    browser. Each person gets their own deadline.
  </Accordion>
</AccordionGroup>

| Setting       | Options                                                            |
| ------------- | ------------------------------------------------------------------ |
| Time zone     | An IANA name such as `Asia/Jerusalem`. Leave empty for the default |
| Format        | Letters (`1d 2h 30m`) or Colons (`01:02:30`)                       |
| Clock text    | Simple text or Flip cards                                          |
| Show units    | Days, Hours, Minutes, Seconds                                      |
| End behaviour | No animation, Flash, Heartbeat or Pulse                            |

<Tip>
  A unit you hide **rolls up into the next one shown**. Hiding days on a
  two-day timer reads as 48 hours rather than losing two days.
</Tip>

Duration and evergreen timers cap at 365 days. A timer with no length and no end date shows a **Set a length or an end date** notice instead of counting.

## Custom HTML / JS

The Custom HTML / JS block takes your own markup in a code editor with syntax highlighting. Scripts inside it run against a small API.

Three things are available to your script:

| Name           | What it is                               |
| -------------- | ---------------------------------------- |
| `document`     | A reference to the popup's isolated root |
| `mainDocument` | The store page's real document           |
| `$senderz`     | Popup data and actions                   |

The `$senderz` object exposes:

```js theme={"system"}
$senderz.data          // the popup, its live state and the variation shown
$senderz.profile       // what is known about this visitor
$senderz.nextStep()
$senderz.previousStep()
$senderz.goToStep(id)
$senderz.close()       // closes the popup completely
$senderz.dismiss()     // closes it and leaves the teaser
$senderz.getVariable(name)
$senderz.setVariable(name, value)
```

Variables you set with `setVariable` are readable from any text block on the popup as `{{variables.name}}`.

Expressions are substituted into your markup and your script before either runs, so `{{email}}` inside custom code resolves the same way it does in a text block.

## Spacing: blocks are full bleed by default

This trips people up more than anything else in the builder, so it is worth stating plainly.

<Info>
  **A block has no padding until you give it some.** Every block reaches the
  edges of the popup card, and every pixel of inset comes from that block's own
  **Block padding** control. There is no built-in gutter, and no per-block-type
  default.
</Info>

The consequence is that a newly added image or coupon box touches the popup edges. That is intentional. It means a full-width hero image needs no fighting, and an inset block shows you exactly where its inset came from.

### The padding control

Block padding starts collapsed, on two inputs:

* **Vertical** sets top and bottom together.
* **Horizontal** sets left and right together.

**All sides** expands it to four inputs: Top, Bottom, Left, Right. **Link sides** collapses it again. A block whose sides are already uneven opens expanded.

Values are whole pixels from **0 to 200**.

<Warning>
  **An explicit `0` is respected and is displayed as `0`.** It is not treated as
  "unset" and quietly replaced with a default. Whatever number the control
  shows is the number that renders, so no spacing is ever invisible.
</Warning>

**Block margin** sits directly below and works identically, in the same units, with the same expand and collapse. Padding is the space inside the block's background; margin is the space outside it.

## Block background

Every block has its own three-way background:

| Mode      | What it paints                                                                     |
| --------- | ---------------------------------------------------------------------------------- |
| **None**  | Nothing. The popup's own background shows through the block                        |
| **Color** | A solid fill behind the whole block                                                |
| **Image** | An image behind the whole block, with a fallback colour wherever it does not reach |

Image mode adds **Fit** (Cover, Contain, Stretch, Original) and a nine-point **Position**.

Two exceptions:

* A **button** paints its own colour, so its field is labelled **Button color** and there is no separate block background.
* The **coupon code** block and every **input field** paint an inner surface on top of the block background. They get an extra **Inner background** setting, so the box inside the block and the block itself can be different colours.

**Radius** rounds the block's corners and applies to the background it paints.

## Show on

Each block carries a **Show on** setting: **All devices**, **Desktop** or **Mobile**.

<Note>
  **Tablets count as desktop.** A block set to Desktop still shows on an iPad.
</Note>

The control only appears when the popup targets more than one device. On a mobile-only popup there is nothing to choose.

## Styling one block, or every block

Every block's Style section starts with a two-button switch:

<CardGroup cols={2}>
  <Card title="This element" icon="crosshairs">
    Changes only this block. Font, size, weight, italic, underline,
    strikethrough, tracking, leading, colour and alignment, plus radius, width
    and height.
  </Card>

  <Card title="Shared style" icon="layer-group">
    Changes the workspace-level style this block inherits, everywhere it is
    used.
  </Card>
</CardGroup>

### The five shared styles

Your workspace has five shared styles. A block resolves which one it uses from its own type, so there is nothing to assign.

| Shared style  | Blocks that use it                   |
| ------------- | ------------------------------------ |
| **Heading 1** | Heading                              |
| **Heading 2** | Subheading, Countdown timer          |
| **Body**      | Text, Inline text                    |
| **Input**     | Email, Phone, Name and Custom fields |
| **Button**    | Button, Plain button, Icon           |

Each carries font, size, weight, style, decoration, letter spacing, line height, colour and alignment. **Reset to default** puts one back to the platform default.

<Warning>
  **Editing a shared style changes every popup that uses it, immediately,
  including live ones.** The panel tells you the blast radius before you save:
  *Editing "Body" changes 41 other elements, across 3 live popups.* Read that
  number. There is no staged rollout for a shared style.
</Warning>

### Which wins

Four layers, narrowest last:

1. The platform default.
2. Your workspace shared style for that role.
3. This popup's own theme, from **Popup styles** on the rail.
4. This block's own style.

A block's own style always wins over the shared style it inherits. That is the point of offering both paths: set the house style once, override the one block that needs to differ.

## Step layouts

Each step has a layout, set in **Step settings** when you click the step tab.

| Layout         | What it does                                                     |
| -------------- | ---------------------------------------------------------------- |
| **Default**    | Blocks stack in a single column                                  |
| **Split**      | The first image moves into its own column beside everything else |
| **Full bleed** | Drops the popup card's own padding for this step only            |

Two rules worth knowing about **Split**:

* **Only the first image moves.** Hoisting every image would relocate a badge or a payment-logo strip you deliberately placed mid-copy.
* If either half would come out empty (no image, or nothing left beside it) the step falls back to a single column rather than rendering an empty half.

**Full bleed** drops the *card* padding only. Block padding is untouched and stays your only source of inset, exactly as in the default layout.

### Desktop and mobile

The layout is set separately per device. Switch the canvas to the mobile preview and the panel shows **Mobile layout** instead.

<Warning>
  **Mobile inherits desktop until you edit it, and then it stops.** The moment
  you edit a step on the mobile canvas, that step gets its own mobile copy of
  its blocks and it is **never re-synced from desktop again**. A field you add
  on desktop afterwards will be missing on mobile, and the publish checks will
  say so.

  The panel tells you which state a step is in, and **Reset to desktop** drops
  the mobile copy so the step inherits again.
</Warning>

Popups have no per-step mobile stacking direction. Use the container's Direction and Reverse order controls, or a separate mobile layout, to change how blocks sit on a phone.

## The teaser

The teaser is the small button that stands in for the popup. It has its own panel, reached from the **Teaser** tab at the start of the step strip or by clicking it on the canvas.

Turn it on with **Show teaser**.

| Section              | Settings                                                                                  |
| -------------------- | ----------------------------------------------------------------------------------------- |
| **Style**            | Rectangle, Circle or Corner. Size Small, Medium or Large                                  |
| **Layout**           | A 3x3 position grid, plus top/bottom and left/right margins                               |
| **Display settings** | When the teaser appears                                                                   |
| **Devices**          | All devices, Desktop or Mobile                                                            |
| **Text**             | Rich text, a screen reader label, font, size and colour                                   |
| **Background**       | Background colour or image, corner radius, drop shadow                                    |
| **Image or icon**    | An image with a description, or one of nine icons, placed before, after or above the text |
| **Close icon**       | An optional dismiss control on the teaser itself, with its own colour                     |

### Position

The grid offers nine anchors: the four corners, the four edge midpoints, and the centre.

<Note>
  A **Corner** teaser is a triangular tab that only reads correctly in a corner,
  so the five non-corner anchors are switched off for it. The panel says so
  rather than silently moving your choice.
</Note>

### Display mode

| Mode                            | Behaviour                                                           |
| ------------------------------- | ------------------------------------------------------------------- |
| **Show after form is closed**   | The default. The teaser reopens the popup once a visitor closes it  |
| **Show before displaying form** | The teaser appears 2 seconds after the page loads                   |
| **Both**                        | It appears 2 seconds after load, and again after the form is closed |

<Info>
  The two "before" modes do **not** suppress the popup's own timing rules. A
  teaser can only ever open the popup **earlier**, never stop it opening on its
  own.
</Info>

### Devices

The teaser's device choice narrows within the popup's own targeting; it never widens it. A popup that does not serve on mobile shows no teaser there either. Tablets count as desktop here too.

## Limits

| Limit                           | Value                           |
| ------------------------------- | ------------------------------- |
| Blocks per step                 | 30                              |
| Blocks inside one container     | 20                              |
| Levels of nesting               | 1 (a group cannot hold a group) |
| Forms per step                  | 1                               |
| Block padding and margin        | 0 to 200 px per side            |
| Countdown length                | 365 days                        |
| Teaser text                     | 2,000 characters                |
| Validation and consent messages | 300 characters                  |

## Related

<CardGroup cols={2}>
  <Card title="Popups and forms" icon="window-restore" href="/en/messaging/popups">
    Steps, triggers, targeting, frequency and installing on your store.
  </Card>

  <Card title="Coupons" icon="ticket" href="/en/messaging/coupons">
    Creating the reward a coupon block hands out, and the unique-code pool.
  </Card>

  <Card title="Consent" icon="shield-halved" href="/en/audience/consent">
    What each consent state means once the visitor has subscribed.
  </Card>

  <Card title="Segments" icon="filter" href="/en/audience/segments">
    Where quiz answers land, and how to use them in a welcome flow.
  </Card>
</CardGroup>
