A page usually answers once. With padSse() in its PHP it keeps the connection open and sends events while they happen - what the browser's EventSource reads, and what htmx's sse extension, a React or an Alpine component listen to. There is no template: the stream is the whole answer.

<?php

  // ticker.php - the producer sends the events itself
  padSse ( function ( $send, $lastId ) {
    foreach ( [ 'one', 'two', 'three' ] as $n => $word ) {
      $send ( 'word', [ 'n' => $n, 'word' => $word ], $n );
      sleep ( 1 );
    }
  }, [ 'retry' => 3000 ] );

?>

The browser side is a few lines, with no library:

const source = new EventSource('?ticker');
source.addEventListener('word', event => show(JSON.parse(event.data)));

On an interval

Given every, PAD calls the producer itself, every so many seconds, and sends what it answers as the event named by event: an array goes as JSON, NULL sends nothing that round, FALSE ends the stream.

<?php

  // stats.php - a fresh number every two seconds, for at most a minute
  padSse ( fn () => [ 'orders' => db ( "FIELD count(*) FROM orders" ) ],
           [ 'every' => 2, 'for' => 60, 'event' => 'stats' ] );

?>
OptionMeaning
everySeconds between two calls of the producer; without it the producer is called once and loops itself
forHow long a stream with every runs at most - 60 seconds unless said otherwise
eventThe name of the event an answer of the producer is sent as - message unless said otherwise
retryMilliseconds the browser waits before it reconnects when the stream ended

What to know

The htmx application streams rows of HTML that its sse extension swaps in (htmx/?examples/live), the Alpine application JSON an EventSource turns into state (alpine/?examples/live).