PAD + Alpine
● Behaviour in the markup

PAD writes the page.
Alpine wakes it up.

Alpine adds behaviour to HTML with a few attributes - and PAD writes that HTML. Both like braces, so the trick is to let each have its own: PAD hands Alpine its state as JSON with the ^ sigil, and longer components live in a file of www/.

<div x-data="{^profile}">          <!-- $profile from the page's PHP -->
  <h2 x-text="name"></h2>
  <button @click="likes++">
    ♥ <span x-text="likes"></span>
  </button>
</div>

The template holds no brace of Alpine's: the state is the JSON of a PHP array.

State from the server

2 examples

Alpine lives in the HTML PAD writes. Its state comes from the page's PHP as JSON in the attribute - the ^ sigil writes it - or as the argument of a component registered in a file of www/.

State from PHP

x-data="{^profile}": the page's PHP prepares an array, the ^ sigil writes it as JSON into the attribute, and Alpine makes it live - no braces of Alpine's in the template at all.

{^field}x-datax-modelx-text

Components in a file

Tabs, an accordion and a dialog registered with Alpine.data in www/alpine/ - the template calls them by name and hands them PAD's data as the argument: x-data="accordion({^faq})".

{^field}{faq}Alpine.datax-showx-transition

Talking back to PAD

4 examples

A component asks the page again: the JSON of $padExpose, a post with the session's token, a stream of events. The server keeps the truth.

Live search

x-model.debounce feeds a fetch of the same page with padFormat=json; the PHP that rendered the first results answers the next ones as JSON - $padExpose names what may leave.

$padExposepadFormat=jsonx-model.debouncex-forfetch

One set of rules

The rules live in the page's PHP: padValidate checks the post with them, padValidateClient hands them to Alpine, and {validator} checks them in the browser first - the same messages on both sides.

padValidateClientpadValidate{validator}@blurpadValidate.check

A list PAD keeps

Every change shows at once and is posted to the page, which keeps the list in the session and answers it - the server's answer is the list. Reload, and it is still there.

padSession$padExposex-for@submit.preventfetch POST

Server-sent events

padSse sends the server's numbers every second as JSON; the component opens an EventSource in x-init and closes it when the stream says it is done.

padSseevery=EventSourcex-init