<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://bridgetownrb.com/" version="2.2.2">Bridgetown</generator><link href="https://www.heartml.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.heartml.dev/" rel="alternate" type="text/html" /><updated>2026-07-22T13:27:48-07:00</updated><id>https://www.heartml.dev/feed.xml</id><title type="html">Heartml</title><subtitle>Make HTML hep to the jive with these postmodern riffs on web dev.</subtitle><entry><title type="html">Ride The Streetcar…All Aboard!</title><link href="https://www.heartml.dev/2026/07/22/ride-the-streetcar-all-aboard/" rel="alternate" type="text/html" title="Ride The Streetcar…All Aboard!" /><published>2026-07-22T11:14:10-07:00</published><updated>2026-07-22T11:14:10-07:00</updated><id>repo://posts.collection/_posts/2026-07-22-ride-the-streetcar-all-aboard.md</id><content type="html" xml:base="https://www.heartml.dev/2026/07/22/ride-the-streetcar-all-aboard/">&lt;p&gt;Oh what fun! &lt;em&gt;Clang clang! Ding ding!&lt;/em&gt; Welcome aboard, one and all!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/docs/ride-the-streetcar&quot;&gt;Ride The Streetcar 🚋&lt;/a&gt;, as part of the Heartml family of vanilla-adjacent web tools, is a new set of client and (optional) server libraries which provide you with a modular &amp;amp; resuable method of driving surgical state changes to your frontend DOM &amp;amp; JavaScript objects.&lt;/p&gt;

&lt;p&gt;Ruby &amp;amp; JavaScript backends are supported out of the gate, and Streetcar is fully compatible with &lt;code class=&quot;highlighter-rouge&quot;&gt;fetch&lt;/code&gt; style techniques as well as &lt;strong&gt;&lt;a href=&quot;https://htmx.org&quot;&gt;htmx&lt;/a&gt;&lt;/strong&gt; via a custom extension. And the Streetcar frontend itself is tiny! &lt;strong&gt;&lt;a href=&quot;https://bundlephobia.com/package/@heartml/streetcar-elements&quot;&gt;Only 2kB minzipped&lt;/a&gt; with &lt;em&gt;zero&lt;/em&gt; dependencies!&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;text-align: center; font-size: var(--wa-font-size-l)&quot;&gt;&lt;a href=&quot;/demos/todo/&quot; class=&quot;wa-button wa-brand&quot; target=&quot;_blank&quot;&gt;Try the Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conceptually, Streetcar is a way of describing actions to be executed on a page using custom elements. You can read a Streetcar payload containing serialized HTML-based statements…aka “streetcar line”…and ideally you’ll understand the operations being performed and in what order. Here’s a basic example:&lt;/p&gt;

&lt;wll-code class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;sc-line&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;sc-query-selector&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;selectors=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#progress-message&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;sc-inner-html&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;em&amp;gt;&lt;/span&gt;Yay!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/em&amp;gt;&lt;/span&gt; Your process is complete. &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Done&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/sc-inner-html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/sc-query-selector&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/sc-line&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/wll-code&gt;

&lt;p&gt;This will select the element in the DOM with &lt;code class=&quot;highlighter-rouge&quot;&gt;id=&quot;progress-message&quot;&lt;/code&gt; and set its inner HTML to the &lt;em&gt;Yay!&lt;/em&gt; markup provided.&lt;/p&gt;

&lt;p&gt;These custom elements aren’t “web components” in the traditional sense. They are non-visual and self-executing in order to translate the serialized logic into JavaScript statements when processed by the client.&lt;/p&gt;

&lt;p&gt;You may be familiar with “pull” based hypermedia tools such &lt;strong&gt;htmx&lt;/strong&gt; (fragment-handling logic is defined client-side) or “push” based tools like &lt;strong&gt;Hotwired Turbo&lt;/strong&gt; (fragment-handling logic is defined server-side). Streetcar is a push-based tool but happy to coordinate with existing pull-based tools—it ships with an htmx extension, and we’re more than willing to help support any other tools in this genre.&lt;/p&gt;

&lt;p&gt;As mentioned above, you can write Streetcar HTML responses using our Ruby or JavaScript helpers:&lt;/p&gt;

&lt;wll-code class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;streetcar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RideTheStreetcar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dsl&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;streetcar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ride&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;query_selector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;#progress-message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inner_html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;em&amp;gt;Yay!&amp;lt;/em&amp;gt; Your process is complete. &amp;lt;button&amp;gt;Done&amp;lt;/button&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/wll-code&gt;

&lt;wll-code class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;streetcar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RideTheStreetcar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dsl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;streetcar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ride&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#progress-message&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;em&amp;gt;Yay!&amp;lt;/em&amp;gt; Your process is complete. &amp;lt;button&amp;gt;Done&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/wll-code&gt;

&lt;p&gt;Streetcar is intended to play nicely with any server capable of sending HTML fragments over the wire…which is virtually any and all of them. We show a few examples of how to use Streetcar with popular &lt;a href=&quot;/docs/ride-the-streetcar/ruby-backend/&quot; class=&quot;wikilink&quot;&gt;Ruby&lt;/a&gt; and &lt;a href=&quot;/docs/ride-the-streetcar/javascript-backend/&quot; class=&quot;wikilink&quot;&gt;JavaScript&lt;/a&gt; frameworks.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Framework-agnostic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Frontend-agnostic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Fully extensible to drive custom logic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Proven techniques based on decades of prior art.&lt;/strong&gt; (&lt;a href=&quot;/docs/ride-the-streetcar/#a-brief-history-%EF%B8%8F&quot; class=&quot;wikilink&quot;&gt;Read a brief history here.&lt;/a&gt;) And maintained by a &lt;a href=&quot;https://www.whitefusion.studio&quot;&gt;trusted voice&lt;/a&gt; in open source application &amp;amp; framework development.&lt;/p&gt;

&lt;p&gt;What’s not to love? 😊&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;We’re excited to learn how you may use Ride The Streetcar! To engage with the Heartml community, &lt;a href=&quot;https://discord.gg/CUuYVH7Qa9&quot;&gt;join the Human Web Collective Discord&lt;/a&gt; where you can meet friendly fellow developers who love investigating and using “vanilla-adjacent” frontend APIs and ask questions about this project and beyond.&lt;/p&gt;

&lt;p&gt;Interested in contributing to Ride The Streetcar? &lt;a href=&quot;https://codeberg.org/heartml&quot;&gt;Bug reports, feature requests, and PRs most welcome.&lt;/a&gt;&lt;/p&gt;</content><author><name>Jared White</name></author></entry></feed>