A program running in a web page reaches the page itself: Page.current() gives the page - its window and document - and from it every element, the address and history, storage, and the window's events. Elements are Elements, events are DomEvents, and timers are Timers on the event loop, so they work the same way in every program. For a page built from components, see browser apps (@app) - they mix with everything here. How the page itself is set up and served is in Websites.
The examples here run on this page: each gets a <div id="app"> to build in, as a page of your own would have in its index.html.
Page.current() is an IOError where there's no page - run under Bun, or on a WASI runtime - so !! ends @main there. Text given to setText, append or an attribute is always text, never markup, so what the user typed can't become part of the page.
find and findAll take CSS selectors, on the page or inside an element; parent, children, next, previous and closest walk from one. Markup goes in only as Html - made with #HTML {{{ }}}, which escapes the values put in it - through setHtml, append, before, after or Page.fromHtml. Two Elements are equal when they're the same element.
There are two ways to hear what happens on the page. on(kind, handler) runs the handler while the event happens, so it can preventDefault() or stopPropagation(), and gives back a Listener to remove():
events(kind) gives an EventQueue instead: events are kept in the order they happened, and an @async loop takes them one at a time with await queue.next() - while it waits, the page carries on, and so does the rest of the program. A queue keeps at most its limit (1000 unless given), dropping the oldest, and close() stops it listening.
A DomEvent is read as it happens: its kind, target, the key and code of a key event, where the pointer was (x, y, button), the modifier keys, a wheel's deltaX and deltaY, and the target's value and checked at that moment. Every element and the window can be listened to, and any other JavaScript event target - a WebSocket, a MediaQueryList - through JsValue.on.
Timer.after(delay, task) runs a task once, Timer.every(interval, task) again and again, and Timer.eachFrame(task) on each frame the display draws - until it's cancelled. Promise.sleep and Promise.nextFrame are the same for an @async function. A timer's task runs on the event loop, between other tasks, never in the middle of one.
In a web page the page's own timers run them - the program never waits, and its @main returns at once while they go on. Anywhere else the event loop waits on &clock for the next one, and the program ends once nothing it waits for is left. Frames are for animation: each task gets the frame's time, in milliseconds.
Timers run on &clock, so a test injects a FixedClock and they run as fast as they come due, in order, with no waiting:
localStorage() keeps text by key across visits, sessionStorage() until the tab is closed; store anything else as JSON. url() is the page's address as a Url; pushHistory and replaceHistory change it without loading anything - a single-page app's routes - and the window's "popstate" event says when the user goes back. navigate loads another page, and alert, confirm and prompt are the browser's dialogs.
element.canvas() gives a <canvas>'s 2D drawing - rectangles, paths, arcs and text in a fill or stroke color (a Color, or any CSS color), moved, turned and scaled, and an Image's pixels put down as they are, with pixels() reading them back. For thousands of shapes each frame, or 3D, draw with the GPU.
The browser has far more than these types cover, and all of it is reachable: any JavaScript object is a JsValue, whose properties are read with get and set with set, whose methods are called with call - a thrown exception comes back as an Error - and which constructs instances when it's a class. toPromise awaits a JavaScript promise; JsValue.callback wraps a Refingere function for JavaScript to call. page.window(), page.document(), element.js() and JsValue.global() are where to start.
What comes back is a number, text, a Boolean or undefined (for null too) as itself, and any object - an Array or a plain object too - as a JsValue, so it stays the very same object; items() and toData() copy one into Refingere values. See JavaScript and TypeScript for writing your own JavaScript and calling it with @js.
In an @app, whatever runs later - a timer's task, a listener, a queued event taken, a JavaScript callback - is followed by rendering again each component it changed, just as an event handler in the markup is:
Page and everything from it needs a web page - compiled to WebAssembly or to JavaScript alike, through the page's own DOM; tests can give a program happy-dom's page. Elsewhere Page.current() is an IOError. Timer works everywhere: on the page's timers in a browser, on &clock anywhere else. See Page, Element and Timer for every member.