Skip to content

Actions and navigation ​

Interactive elements run actions from their on= prop: buttons, links, pressable cards and list items, and controls after their value changes.

ActionEffect
inc:key or inc:key:byAdd 1, or by
dec:key or dec:key:bySubtract 1, or by; never below 0
toggle:keyFlip true and false
set:key:valueSet a literal, or an expression: set:total:{a + b}
emit:name or emit:name:valueTell the host app what the person chose
go:screenShow another screen
backReturn to the previous screen
notify:'message'Show a short message for a few seconds; it can include {expressions}
add:list:valueAdd an item to the end of a list
remove:t or remove:list:indexRemove the current item inside each, or the item at a position
clear:listEmpty a list

The key of inc, dec, toggle and set can be a path, like toggle:t.done. A quoted value is text: set:msg:'Hi there'.

Several actions ​

Separate them with ;, and quote the whole value. They run in order:

sayshape
state items=0
card
  text "{plural(items, 'item')} in your cart"
  button "Add to cart" on="inc:items;notify:'Added. {items} in your cart'"
  button "Empty cart" variant=secondary on="set:items:0;notify:'Cart emptied'" disabled={items == 0}
Rendered by the SayShape engineOpen in playground

Talking to the host ​

emit is how an interface hands something to the app around it. The engine fires an action event with the name and value; what happens next is up to your app.

sayshape
state qty=2 placed=false
card
  stepper "Quantity" bind=qty min=1 max=5
  button "Place order" on="set:placed:true;emit:order:{qty}" disabled=placed
  text "Order sent to the app." tone=good if=placed
Rendered by the SayShape engineOpen in playground
ts
ui.on("action", ({ name, value }) => {
  if (name === "order") submitOrder(value); // your code; SayShape never calls a server itself
});

On this website nothing listens for these events except a log that shows them. Every submission in the docs and examples is simulated.

A value can be a record built from state: emit:request:{item: item, qty: qty} sends { item: "…", qty: 2 }.

Screens ​

A spec can hold several screens. Only one shows at a time: the first, until an action moves to another with go:name. back returns to the previous one.

sayshape
state qty=1
screen name=product title="Trail socks"
  stepper "Quantity" bind=qty min=1
  button "Add to cart" on=go:cart
screen name=cart title="Your cart"
  text "{qty} pairs"
  button "Keep shopping" variant=secondary on=back
Rendered by the SayShape engineOpen in playground

State is shared by every screen. Screens only go at the top level, and their names are plain words (letters, digits and _). go: to a screen that doesn't exist does nothing. The visible screen's name is in {screen}. Your app can move between screens with ui.go("cart") and ui.back(), and hears every move through the navigate event.

Messages ​

notify shows a message at the bottom of the visible area, drawn by the engine in the theme's colors, and fires a notify event so your app can announce it too. Quote the message when it has spaces or ;.

SayShape v0.1 is an early prototype under the MIT License. Status · GitHub