Skip to content

Actions ^0.11.0 experimental ​

Actions are HTML attributes that write a state when an event fires. A button that only opens a menu or counts a click needs no JavaScript of its own.

erb
<%# herb:slots client %>
<%# herb:state (open: false) %>

<button data-herb-toggle="open">Menu</button>
<% if open %><nav>Links</nav><% end %>

Attributes ​

AttributeWritesState kind
data-herb-setname=valueany
data-herb-toggleflips true and falseBoolean
data-herb-incrementadds data-herb-by, or 1Integer
data-herb-decrementsubtracts data-herb-by, or 1Integer
data-herb-resetthe declared defaultany
data-herb-actionruns a built-in actionnone

Each takes a comma-separated list, so one click can write several states as a single update.

erb
<%# herb:slots client %>
<%# herb:state (pending: false, failed: false, attempts: 0, draft: "") %>

<button data-herb-set="pending=false,failed=true">Retry</button>
<button data-herb-increment="attempts" data-herb-by="2">More</button>
<button data-herb-decrement="attempts">Fewer</button>
<button data-herb-reset="draft">Clear</button>
<button data-herb-reset>Start over</button>
<p><%= attempts %> attempts</p>
<% if pending %><p>Sending</p><% end %>
<% if failed %><p>Failed</p><% end %>
<input value="<%= draft %>">

data-herb-reset with no value resets every state in the element's scope.

data-herb-set ​

Sets one or more states to a value.

erb
data-herb-set="name=value"
data-herb-set="name=value,name=value"
data-herb-set="event->name=value"

The value is read as the state's kind, so pending=true sets a Boolean and draft=true sets the String "true". Quote a String value that holds a comma or a space, as in draft='hello, world'.

$value stands for the value of the element the event fired on, and it is the only interpolation. A set with no value, such as data-herb-set="open", is reported by the linter and by the client in debug mode.

erb
<%# herb:slots client %>
<%# herb:state (sort: "name") %>

<select data-herb-set="change->sort=$value">
  <option value="name">Name</option>
  <option value="date">Date</option>
</select>
<p>Sorted by <%= sort %></p>

data-herb-action ​

Runs a built-in action. $refresh asks the server to render the server-derived parts of the page again with the current states.

erb
<button data-herb-action="$refresh">Reload</button>

Actions you define yourself are not available yet.

Events ​

An action runs on the default event for its element unless a clause names one.

ElementDefault event
<form>submit
<input>, <textarea>input
<input> of type submit, button or resetclick
<select>change
<details>toggle
anything elseclick

A clause is event->operation. Separate several clauses with a space.

erb
<div data-herb-set="mouseenter->menu=true mouseleave->menu=false">Account</div>
<input data-herb-reset="blur->draft">

Keys and modifiers ​

keydown, keyup and keypress take a key after a dot. Modifiers join the key with +.

erb
<input data-herb-reset="keydown.esc->draft">
<button data-herb-set="keydown.meta+k@window->palette=true">Search</button>
Key aliasKey
escEscape
returnEnter
spaceSpace
up, down, left, rightthe arrow keys
page_up, page_downPage Up, Page Down

Modifiers are meta (or cmd), ctrl, alt and shift. A modifier may also go before any other event, as in shift+click. An action with a modifier prevents the browser's default for that event.

Where the event is heard ​

SuffixRuns for
noneevents on the element
@window, @documentevents anywhere on the page
@outsideevents anywhere on the page except inside the element
erb
<div data-herb-set="click@outside->open=false keydown.esc@window->open=false">Menu</div>

Timing ​

AttributeTakesDoes
data-herb-debouncemillisecondsWaits until the events stop for this long, then runs once
data-herb-throttlemillisecondsRuns at most once in this long
erb
<input value="<%= query %>" data-herb-set="query=$value" data-herb-debounce="250">

Scope ​

An action writes the nearest state with that name, looking outward from the element. Inside a keyed row that is the row's state, and outside it is the template's. A derived state cannot be written.

What is checked where ​

The engine compiles any action attribute, so mistakes in one are reported by the linter and by the client in debug mode. Both flag a state name that is not declared in an enclosing scope, an operation that does not match the kind such as data-herb-toggle on an Integer, and a set value that does not parse as the kind such as attempts=lots. They also flag a key filter on an event that is not a key event, a target other than @window, @document and @outside, and any write to a derived state.

Released under the MIT License.