<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;">
<what-info-box><br>
<what-stat-card><br>
<what-user-profile>
</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><what></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><!-- components/info-box.html -->
<what>
props = "type, title"
defaults.type = "info"
</what>
<div class="info-box-#type#">
<strong>#title#</strong>
<slot/>
</div></code></pre>
<p class="text-sm text-gray-500 mt-2">
<code><slot/></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><what-info-box type="info" title="Information">
This is an informational message.
</what-info-box>
<what-info-box type="warning" title="Watch out">
This uses type="warning".
</what-info-box>
<what-info-box type="success" title="All good">
And type="success" for green.
</what-info-box></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><!-- components/stat-card.html -->
<what>
props = "label, value, color"
defaults.color = "indigo"
</what>
<div style="border-left: 3px solid #color#; ...">
<div class="stat-value">#value#</div>
<div class="stat-label">#label#</div>
</div>
<!-- Usage -->
<what-stat-card label="Users" value="1,024"></what-stat-card>
<what-stat-card label="Revenue" value="$42k" color="green"></what-stat-card></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><if></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><!-- Inside a component: conditionals on props -->
<if color == green>
<!-- Green styling -->
</if>
<if color == red>
<!-- Red styling -->
</if></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><!-- site/tutorial/application.what -->
layout = "components/tutorial-layout.html"
<!-- site/tutorial/3.html -->
<what>
active_step: 3
title: "Step 3 — Components"
</what></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><what-name></code></li>
<li>Props are declared in the <code><what></code> block with <code>props = "a, b"</code></li>
<li>Default values: <code>defaults.type = "info"</code></li>
<li><code><slot/></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>