run-what 1.3.0

HTML-first web framework powered by Rust. No JavaScript frameworks, no build steps—just HTML.
<what>
title: "Step 3 — Components"
active_step: 3
</what>

<h1 class="text-3xl font-bold mb-2" style="color: #111827; letter-spacing: -0.02em;">Step 3 — Components</h1>
<p class="text-gray-500 text-sm mb-8">HTML files in <code>components/</code> become custom tags.</p>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">How components work</h2>
  <p class="text-gray-600 mb-4" style="line-height: 1.7;">
    Any <code>.html</code> file in your <code>components/</code> directory becomes a usable custom tag. The filename maps to the tag name with a <code>what-</code> prefix.
  </p>
  <div class="card mb-4">
    <div class="card-body">
      <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem;">
        <div style="background: #f9fafb; border-radius: 0.375rem; padding: 0.75rem;">
          <div class="text-xs text-gray-400 mb-2 uppercase font-semibold tracking-wide">File</div>
          <div class="font-mono text-sm text-gray-700" style="line-height: 2;">
            components/info-box.html<br>
            components/stat-card.html<br>
            components/user-profile.html
          </div>
        </div>
        <div style="background: #f9fafb; border-radius: 0.375rem; padding: 0.75rem;">
          <div class="text-xs text-gray-400 mb-2 uppercase font-semibold tracking-wide">Tag</div>
          <div class="font-mono text-sm text-indigo-600" style="line-height: 2;">
            &lt;what-info-box&gt;<br>
            &lt;what-stat-card&gt;<br>
            &lt;what-user-profile&gt;
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Props and defaults</h2>
  <p class="text-gray-600 mb-3" style="line-height: 1.7;">
    The <code>&lt;what&gt;</code> block inside a component declares its props and default values. Props become template variables inside the component.
  </p>
  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;!-- components/info-box.html --&gt;
&lt;what&gt;
props = "type, title"
defaults.type = "info"
&lt;/what&gt;
&lt;div class="info-box-#type#"&gt;
  &lt;strong&gt;#title#&lt;/strong&gt;
  &lt;slot/&gt;
&lt;/div&gt;</code></pre>
  <p class="text-sm text-gray-500 mt-2">
    <code>&lt;slot/&gt;</code> is where child content goes when you use the component.
  </p>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Live example — the info-box component</h2>
  <p class="text-gray-600 mb-4" style="line-height: 1.7;">
    This project includes a <code>components/info-box.html</code> component. Here it is in use with three different <code>type</code> prop values:
  </p>

  <what-info-box type="info" title="Information">
    This is an informational message. The <code>type="info"</code> prop gives it a blue style.
  </what-info-box>

  <what-info-box type="warning" title="Watch out">
    This uses <code>type="warning"</code>. The component switches its color based on this prop.
  </what-info-box>

  <what-info-box type="success" title="All good">
    And <code>type="success"</code> for green. One component, three looks — driven by props.
  </what-info-box>

  <pre class="bg-gray-50 p-4 rounded text-sm font-mono mt-4" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;what-info-box type="info" title="Information"&gt;
  This is an informational message.
&lt;/what-info-box&gt;

&lt;what-info-box type="warning" title="Watch out"&gt;
  This uses type="warning".
&lt;/what-info-box&gt;

&lt;what-info-box type="success" title="All good"&gt;
  And type="success" for green.
&lt;/what-info-box&gt;</code></pre>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Stat card — a second component</h2>
  <p class="text-gray-600 mb-3" style="line-height: 1.7;">
    This project also includes a <code>components/stat-card.html</code> component with <code>label</code>, <code>value</code>, and <code>color</code> props. Here are four live instances:
  </p>

  <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-bottom: 1rem;">
    <what-stat-card label="Users" value="1,024" color="indigo"></what-stat-card>
    <what-stat-card label="Revenue" value="$42k" color="green"></what-stat-card>
    <what-stat-card label="Errors" value="3" color="red"></what-stat-card>
    <what-stat-card label="Pending" value="17" color="amber"></what-stat-card>
  </div>

  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;!-- components/stat-card.html --&gt;
&lt;what&gt;
props = "label, value, color"
defaults.color = "indigo"
&lt;/what&gt;
&lt;div style="border-left: 3px solid #color#; ..."&gt;
  &lt;div class="stat-value"&gt;#value#&lt;/div&gt;
  &lt;div class="stat-label"&gt;#label#&lt;/div&gt;
&lt;/div&gt;

&lt;!-- Usage --&gt;
&lt;what-stat-card label="Users" value="1,024"&gt;&lt;/what-stat-card&gt;
&lt;what-stat-card label="Revenue" value="$42k" color="green"&gt;&lt;/what-stat-card&gt;</code></pre>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Components with conditionals</h2>
  <p class="text-gray-600 mb-3" style="line-height: 1.7;">
    Components can use <code>&lt;if&gt;</code> inside their template to conditionally render parts based on prop values. The stat-card uses this to pick a border color. The info-box uses it for its background.
  </p>
  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;!-- Inside a component: conditionals on props --&gt;
&lt;if color == green&gt;
  &lt;!-- Green styling --&gt;
&lt;/if&gt;
&lt;if color == red&gt;
  &lt;!-- Red styling --&gt;
&lt;/if&gt;</code></pre>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">This page uses a component too</h2>
  <p class="text-gray-600 mb-3" style="line-height: 1.7;">
    The sidebar navigation you're looking at right now is <code>components/tutorial-layout.html</code>. It receives an <code>active_step</code> prop from each page, highlights the correct nav item, and renders the prev/next footer. The layout is assigned via <code>site/tutorial/application.what</code>.
  </p>
  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;!-- site/tutorial/application.what --&gt;
layout = "components/tutorial-layout.html"

&lt;!-- site/tutorial/3.html --&gt;
&lt;what&gt;
active_step: 3
title: "Step 3 — Components"
&lt;/what&gt;</code></pre>
</section>

<div class="card" style="border-color: #bbf7d0; background: #f0fdf4;">
  <div class="card-body">
    <div class="text-sm font-semibold mb-2" style="color: #14532d;">What you learned</div>
    <ul class="text-sm space-y-1" style="color: #166534; padding-left: 1.25rem; list-style: disc;">
      <li><code>components/name.html</code> becomes <code>&lt;what-name&gt;</code></li>
      <li>Props are declared in the <code>&lt;what&gt;</code> block with <code>props = "a, b"</code></li>
      <li>Default values: <code>defaults.type = "info"</code></li>
      <li><code>&lt;slot/&gt;</code> is where child HTML goes inside a component</li>
      <li>Components can use conditionals to vary output based on props</li>
      <li>Components can receive variables as props, not just strings</li>
    </ul>
  </div>
</div>