# Effective _hyperscript
A practical reference for writing _hyperscript - a scripting language for the web designed to be embedded in HTML.
## Core Concepts
_hyperscript code lives in `_` attributes on HTML elements. Each element's script defines **features** (event handlers,
functions, variables) that operate on that element.
```html
```
The language reads like English. Prefer natural phrasing over terse syntax.
## Style: Write English, Not Code
### `the` - Semantic Sugar
The word `the` can be inserted almost anywhere for readability. It has no semantic meaning and is ignored by the parser:
```hyperscript
-- These are identical:
set innerHTML of #d1 to "hello"
set the innerHTML of the #d1 to "hello"
get the first
in the
get first in
```
Always use `the` when it makes the line read more naturally.
### Property Access: Prefer English Order
_hyperscript offers three ways to access properties. Prefer the most readable form:
**Possessives** - the standard form. Use `'s` for named elements, and `my`, `its`, `your` for the special implicit targets:
```hyperscript
set #output's innerHTML to "done"
get the event's detail
set the closest 's style to ""
set my innerHTML to "hello" -- "my" refers to me
put its name into me -- "its" refers to it (the result)
log your style.color -- "your" refers to you (in tell blocks)
```
**`of` expressions** - an alternative form that is particularly useful when you want to avoid the tight binding of possessives, since `of` binds more loosely:
```hyperscript
-- without "of", you'd need parentheses:
get (the closest
)'s children
-- with "of", it reads naturally:
get the children of the closest
```
**Dot notation** - good for method invocation and acceptable in general, although the other forms are preferred for readability:
```hyperscript
element.classList.add('active') -- method calls: dot is natural
element.dataset.id -- deeply nested access: dot is practical
my.style.color -- acceptable but "my style's color" is more hyperscript-y
```
**Guideline:** If you can read the line aloud and it sounds like English, you've picked the right form. `#output's innerHTML` reads better than `#output.innerHTML`. Use `of` when possessives would require parentheses.
## Magic Symbols
| Symbol | Meaning |
|---------------------------|----------------------------------------------|
| `me`, `my`, `I` | The element the script is on |
| `it`, `its`, `result` | Result of the last command |
| `you`, `your`, `yourself` | Current target in a `tell` block |
| `event` | The current event object (in `on` handlers) |
| `target` | `event.target` |
| `detail` | `event.detail` |
| `sender` | Element that sent a custom event |
| `body` | `document.body` |
| `cookies` | Cookie jar (get/set/clear) |
| `clipboard` | System clipboard (async read, sync write) |
| `selection` | Currently selected text (`window.getSelection().toString()`) |
## Variable Scoping
```hyperscript
set x to 1 -- local to this handler invocation
set $x to 1 -- global (window-level)
set :x to 1 -- element-scoped (persists across handler calls)
set element x to 1 -- same as :x
set global x to 1 -- same as $x
set local x to 1 -- explicitly local
```
Element-scoped variables (`:x`) persist between event handler invocations on the same element. Use them for component
state.
### DOM-Scoped Variables
```hyperscript
set ^x to 1 -- DOM-scoped: walks up the DOM to find/set the variable
```
DOM-scoped variables (`^x`) search up the DOM tree for the nearest element that has that variable defined. They are
used for component state and for sharing state within a section of the page without using globals. Each component
instance gets its own isolated DOM scope via `dom-scope="isolated"`.
```html
0
```
## Features
### Event Handlers - `on`
```hyperscript
on click ...
on click from #other-element ...
on click from closest ...
on keyup[key is 'Escape'] ... -- event filtering
on click(clientX, clientY) ... -- destructure event properties
on every click ... -- allow concurrent handlers
on first click ... -- fire only once
on click debounced at 300ms ...
on click throttled at 500ms ...
on click queue all ... -- queue: all, first, last (default), none
```
Observers - mutation, intersection, and resize:
```hyperscript
on mutation of @class from #target ...
on mutation of anything ... -- watch all changes
on intersection(intersecting) having threshold 0.5 ...
on resize put detail.width into #size ... -- ResizeObserver, detail has width/height
```
### Function Definitions - `def`
```hyperscript
def greet(name)
return "Hello, " + name
end
def utils.format(x) -- namespaced function
return x as String
end
```
Functions support bare `return` (returns null), `catch` and `finally`:
```hyperscript
def riskyOp()
if not ready return end -- early return, no value
throw "oops"
catch e
log e
finally
log "done"
end
```
### Behaviors - `behavior` / `install`
Reusable bundles of features:
```hyperscript
behavior Removable(removeButton)
on click from removeButton
remove me
end
end
```
```html
```
### Init Blocks - `init`
```hyperscript
init
add .loaded to me
end
init immediately -- runs before other features are installed
set :count to 0
end
```
### Element Variables - `set` (feature level)
```hyperscript
set :count to 0 -- element-scoped, available to all handlers
```
### Inline JavaScript - `js` (feature level)
```hyperscript
js
function helper() { return 42; }
end
```
Exposed functions become globally available.
## Commands
### Assignment
```hyperscript
set x to 10
set my.style.color to "red"
set #d1's innerHTML to "hello"
set innerHTML of #d1 to "hello"
set @data-value to "foo"
set *color to "red" -- style ref
set arr[0] to "first"
set {foo: 1, bar: 2} on myObj -- bulk property set
default x to 10 -- only sets if x is null or empty string
put "hello" into me -- DOM-aware: clears children, inserts as HTML
put "hello" before me -- DOM insertion
put "hello" after me
put "hello" at start of me
put "hello" at end of me
put "hello" into x -- if x is an Element, clears and inserts
put "hello" into my.innerHTML -- property assignment
put null into @foo -- removes the attribute
put item at start of myArray -- unshift
put item at end of myArray -- push
increment x -- +1
increment x by 5
decrement x -- -1
decrement x by 3
```
### DOM Manipulation
```hyperscript
add .active -- to me (default)
add .active to #target
add .foo .bar to -- multiple classes
add @disabled to me
add {color: red; font-size: 2em} to me -- inline styles
add .highlight to when it is not me
add item to myArray -- push to array
add item to mySet -- add to set
remove .active
remove .active from #target
remove @disabled from me
remove {color; font-size} from me -- remove CSS properties
remove me -- removes the element from DOM
remove item from myArray -- find by value and splice
remove item from mySet -- set.delete(item)
remove key from myMap -- map.delete(key)
toggle .active -- on me
toggle .active on #target
toggle .active for 2s -- auto-toggles back
toggle .active until mouseout
toggle between .on and .off
toggle between @open="true" and @open="false"
toggle *display -- visibility toggle
toggle *opacity of #target
take .active from .tabs for me -- removes from all .tabs, adds to me
show me -- display: block (or showModal for