Cheat Sheet

All of JAF's syntax on one page.

Reactivity

SyntaxMeaning
let x = 0Reactive variable
const x = 0Static constant
let doubled = count * 2Derived value, updates itself
const doubled = computed(() => count * 2)Explicit computed, read .value
effect(() => { ... })Side effect, re-runs on change

Templates (JEX)

SyntaxMeaning
{expression}Text expression
attr={expression}Attribute expression
attr="{static} {expr}"Mixed attribute
{cond ? <A /> : <B />}Conditional
{cond && <A />}Show or hide
{items.map(i => <li>{i}</li>)}List
key={item.id}Keyed list item. Add it whenever the list can reorder

Directives

DirectiveExample
class:class:active={isActive}
style:style:color={textColor}
bind:bind:value={name}
on:on:click|preventDefault={handler}
ref:ref:inputRef
use:use:autofocus
transition:transition:fade, slide, scale, class="..."

animate:, in: and out: do not exist, and writing one is a build error. A directive on a component tag is a build error too - the exception is bind:, which syncs a prop rather than decorating an element. See the Directives Reference.

bind: by control

ControlWhat the variable holds
<input>, <textarea>A string
<input type="number">A number, or null while empty
<input type="checkbox" bind:checked>A boolean
<select>The chosen value
<select multiple>An array. Initialise it []
A radio groupOne variable across the group, holding the chosen radio's value
<details>, <dialog> with bind:openA boolean

Events

SyntaxMeaning
onclick="count++"Inline expression
onclick="handleClick()"Function call
onclick="handleClick"Bare name, called for you
onclick={() => fn(x)}Arrow: binds arguments, receives the event
on:click|mod={fn}With modifiers

Modifiers: preventDefault · stopPropagation · once · self · capture · passive

Keys: escape · enter · tab · space · up · down · left · right · delete · backspace · ctrl · alt · shift · meta.

There are no letter keys.

Every modifier works wherever a handler compiles, rows and control-flow arms included. A handler on a component tag - <Button onclick="go()"> - compiles too: it is your component's code, attached to the child's root element, and never a prop. It needs the child to have one root element.

Components

SyntaxMeaning
<Component />Use a component. Filename is the tag name
<Component prop="value" />Static prop
<Component prop={expr} />Dynamic prop
<Component>content</Component>With children
<slot />Default slot
<slot name="x" />Named slot
<div slot="x">Fill a named slot

Built-in components

No import. Both casings work, apart from <Menu>.

ComponentPurpose
<show>Conditional, with a fallback
<for>Keyed list iteration
<switch> / <match>Multi-branch conditional
<dynamic>Tag or component chosen at runtime
<teleport>Render elsewhere in the DOM
<suspense>Boundary for loading content
<error-boundary>Catch errors, show a fallback
<guard>Access control
<Layout>Inherit the parent layout. Must be the whole top-level content of a layout.html; src= names an explicit parent
<Modal>, <Drawer>, <Popover>, <Tooltip>, <Menu>, <ToastHost>Overlays

None of them renders a wrapper element: an arm, a row and a mounted component are inserted at a comment anchor, so what the page contains is the markup you wrote.

A <for> fallback has its expressions compiled. Every other fallback - <show>, <switch>, <suspense>, <error-boundary> - is literal markup, and an expression or a component tag in one is a build error.

State

SyntaxMeaning
let x = storage(default)Persist to localStorage
let x = url(default)Sync with a query param named after the variable
let x = url('key', default)Query param with your own key
let x = path('/docs', default)Sync with a URL path segment
let x = unite(ns.var)Share with another file

Data fetching

SyntaxMeaning
query('/api/x')Fetch, keyed by URL
query('key', '/api/x')Named query, so a mutation can invalidate it
mutation('/api/x', opts)Write, with method and invalidates
q.data · q.loading · q.errorReactive state
q.refetch() · m.mutate(input)Run it

Lifecycle

SyntaxMeaning
<script>Setup. Runs before the DOM exists
onMount(() => {})After the DOM and its bindings are ready
onNavigate((path) => {})On every route change while mounted
onDestroy(() => {})Cleanup on unmount
effect(() => {})Reactive side effect
<script once>Runs once for the whole app

Routing

FileRoute
pages/index.html/
pages/about.html/about
pages/users/[id].html/users/:id
pages/layout.htmlLayout wrapper
SyntaxMeaning
<a href="/about">Navigation. There is no Link component
route.path · route.params.id · route.queryCurrent route, reactive
navigate(path, opts)Navigate in code. Import from jafjs/router

UI controller

APIMeaning
ui.modal.open(name) · ui.modal.close()Open and close
ui.modal.isOpen(name)Reactive check
ui.drawer.toggle(name)Toggle a drawer
ui.popover.toggle(name, anchor)Toggle a popover
ui.toast.show(msg, opts)Show a toast
await ui.confirm(msg)A dialog that resolves

Styles and script attributes

SyntaxMeaning
<style>Scoped to this component
<style global>Not scoped
<script once>Run once for the whole app
<script no-forward>Do not forward unknown props to the root element