Skip to content
Design

Interactions

Menus that open, buttons that react, lists that load more. Build them in a block's Interact tab, without writing code.

On this page

Interactions make your pages respond to visitors: a menu that opens on a phone, a header that shrinks as you scroll, a "Load more" button under a blog list. You build them in a block's Interact tab, under its animations.

A heading selected on the home page, with its Interact settings open on the right.

Pages without interactions load no JavaScript at all.

#How it works

An interaction has three parts. State remembers something, like whether the menu is open. Events change it, like a click on the menu button. And blocks react to it: the menu shows while it's open.

#Build a mobile menu

Here's the whole thing, start to finish. You need a header that holds a menu button and the menu itself.

  1. Remember whether it's open. Select the header, open Interact, and under State press Add Variable. Name it open, with the value false.
  2. Open and close it. Select the menu button. Under Events, press Add Event and keep Click. Press Add Action and choose Toggle State, then the variable open.
  3. Show the menu while it's open. Select the menu. Under Bindings, set Show When to open, and pick the Collapse transition.
  4. Close it with Escape. Select the header again and add an event: Key Pressed, with the key escape. In its options, choose Anywhere on the Page. Add the action Set State: open to false.
  5. Tell screen readers. On the menu button, under Bindings → Attributes, press Bind Attribute and set aria-expanded to open.

Choose Preview in More Actions, the ⋯ at the top of the editor, to try it.

#State

Variables that a block and everything inside it can read and change: open set to false, tab to 'overview', count to 0. Values are true or false, numbers, quoted text, or JSON lists and objects.

Put the variable on the block that holds everything that needs it, like the header for a mobile menu.

#Events

An event runs a list of actions, one after the other, when something happens.

EventWhen
Click, Pointer Enters, Pointer LeavesThe pointer clicks, or moves over or off the block
Gets Focus, Loses FocusKeyboard or pointer focus arrives or leaves
Typing, Value Changes, Form SubmitIn inputs and forms
Key PressedA key, like escape, enter, k or meta.k
Scrolls into View, Scrolls Out of ViewThe block enters or leaves the screen
Page Scrolls, Window ResizesOn the whole window
Page LoadsWhen the block starts

The options of an event (the sliders icon) fine-tune it: Prevent Default, Stop Propagation, Outside This Element (to close a menu when visitors click elsewhere), Anywhere on the Page, Only Once, On This Element Only and Debounce.

#Actions

ActionDoes
Set StateSets a variable: open to false, tab to 'pricing', count to count + 1
Toggle StateFlips a true or false variable
Add to NumberAdds to (or subtracts from) a number
If … Then … ElseRuns one list of actions or another, depending on a condition
Play AnimationPlays, reverses, toggles or restarts a block's animation with the On Event trigger
Scroll ToThe top or bottom of the page, a section or a block, with an offset for sticky headers
Load Page PartFetches a page and swaps in the blocks you choose from it
Copy to ClipboardA value, or a block's text
Go to LinkOpens a link, optionally in a new tab
Light or Dark ModeSwitches, or sets light, dark or the system's choice. Remembered across visits
Focus ElementMoves keyboard focus to a block
Lock Page ScrollingStops the page scrolling behind a modal or a full-screen menu, or lets it scroll again
WaitPauses before the next action
Send EventSends a named event that other blocks can listen for
ExpressionAnything else, written as an expression

Conditions and values are short expressions: open, !open, tab === 'a', count > 3 && ready, query.length.

#Bindings

Under Bindings, a block reacts to its variables:

  • Show When shows the block only while a condition is true, with an optional Fade, Scale or Collapse transition. To select a block it hides, use the Outline in the sidebar.
  • States add a custom state while a condition is true, like open. Style it in Design, and style children with in open: see Custom states.
  • Text replaces the block's text with a value, like count.
  • Attributes keep aria-expanded, aria-selected, hidden, disabled, href and others in sync with a variable.
  • Input Value, on an Input block, keeps a variable in sync with what visitors type. Use it for live filters and calculators.

#Behaviors

Ready-made interactions you switch on under Behaviors:

BehaviorDoes
Scroll StatesGives the block the state scrolled once the page scrolls past a distance you set, and optionally hidden while scrolling down. For headers that shrink or hide
Scroll SpyLinks inside to #sections get the state current while their section is in view. For tables of contents
Hover GroupBlocks inside can react when the whole block is hovered, with the Hover on Hover Group state
MenuA navigation menu with one panel that moves between items. Each child is a link or button, with an optional panel after it. A pill follows the pointer and keyboard focus, the panel's background changes shape to fit the next item, and its content cross-fades. Escape closes it, the Down arrow goes into it, and it respects reduced motion
MarqueeThe children scroll sideways in an endless loop, at a Speed in pixels per second, optionally reversed and paused on hover
CarouselA row to step through. The first child scrolls sideways (give it overflow and scroll snap in Design), and the first two buttons after it go back and forward by one item. A button is disabled at its end of the row. Blocks with a data-carousel-to attribute are thumbnails: each goes to the item in its own position, and has data-current while that item shows

#Load more without a reload

Links, buttons and forms can load the next page in the background and swap in only some blocks, without a full reload. Use it for Load more buttons, filters, and tabs with their own links.

  1. Select the link or button, and open Load Into in its Interact tab.
  2. Under Update, add the blocks to swap.
  3. Turn on Update the Address Bar to keep the link shareable.
  4. On each block you swap, When Loaded in the same section decides how the new content arrives: Replace It (the default), Replace What Is Inside, Add to the End, Add to the Start or Morph (Keep State).

A "Load more" button under a paginated blog list is a Link connected to Next Page of a List, loading into the Repeat, with the Repeat set to add to the end. Load Into shows on links, buttons and boxes, so a Repeat's setting is stored as "merge": "append" in its logic: ask the assistant to set it, or see For developers. Without JavaScript, the link simply opens the next page.

#Tabs

For tabs, use the Tabs block instead of building them from state. Add a Tab per panel, and put anything in it. Look chooses underlined tabs, a segmented control, or a column of tabs beside the panels, which becomes a row on a phone.

Tabs follow the ARIA tabs pattern, with arrow keys, Home and End. Find in page opens the panel it finds something in, and so does a link to something inside one. Without JavaScript every panel shows, one after the other, under its label. In the editor all panels show, so you can select each one.

#Code components

When something can't be built from state, events and actions, like a calculator, a chart or a third-party widget, a developer can write it as a small component in the site's custom JavaScript. Name it under Interact → Code Component. The block then uses that component instead of its own State; everything inside can read its values and call its functions, and the other interaction settings keep working. See Custom CSS and JavaScript.

#For developers

#What runs on the site

Interactions run on Alpine.js, in its CSP build, which never evaluates free-form JavaScript, plus Alpine AJAX for Load Into and Load Page Part. Expressions are Alpine's; the CSP build has no access to window, document or other globals and no arrow functions, so editors can't run arbitrary code. Developers add JavaScript in custom.js.

#The mobile menu, as stored

JSON
{
  "type": "box", "props": { "tag": "header" },
  "logic": {
    "data": { "open": false },
    "states": { "open": "open" },
    "on": [{ "event": "keydown", "key": "escape", "mods": ["window"], "actions": [{ "do": "set", "var": "open", "value": "false" }] }]
  },
  "children": [
    { "type": "box", "props": { "tag": "button" }, "attrs": { "aria-label": "Menu" },
      "logic": { "attrs": { "aria-expanded": "open" }, "on": [{ "event": "click", "actions": [{ "do": "toggle", "var": "open" }] }] },
      "children": [{ "type": "icon", "props": { "icon": "list" } }] },
    { "type": "box", "props": { "tag": "nav" }, "logic": { "show": "open", "transition": "collapse" }, "children": [] }
  ]
}

#All logic settings

JSON
{
  "data": { "tab": "monthly" },
  "on": [{ "event": "click", "mods": ["prevent"], "actions": [
    { "do": "set", "var": "tab", "value": "'yearly'" },
    { "do": "if", "test": "tab === 'yearly'", "then": [{ "do": "play", "node": "b9x2k4", "motion": "m1", "mode": "restart" }], "else": [] }
  ] }],
  "show": "tab === 'yearly'", "transition": "fade",
  "states": { "active": "tab === 'yearly'" },
  "text": "count",
  "attrs": { "aria-pressed": "tab === 'yearly'" },
  "model": "query",
  "target": ["b4m1q8"], "push": true, "merge": "append",
  "behaviors": { "scroll": { "threshold": 40, "hide": true }, "spy": { "offset": 96 }, "group": true, "carousel": {}, "marquee": { "speed": 60 } }
}
  • Events: click, mouseenter, mouseleave, focus, blur, input, change, submit, keydown (with key), enter, leave, scroll, resize; Page Loads is stored as init, a list of actions.
  • Event options (mods): prevent, stop, outside, window, once, self, debounce.
  • Action types: set, toggle, add, if, wait, play, scroll, copy, go, theme, focus, dispatch, fetch, lock and run.
  • states add is-<name>; model is Input Value; target, push and merge are Load Into; component names a code component.

Lettern checks every value when it is saved; blocks/types lists the events, options, actions and transitions for agents.