.slurp file included from another file. It takes props,
renders markup, and can accept children through a <slot />.
Declaring a component
Components live incomponents/, where they are checked but never emitted as a
page.
components/Card.slurp
index.slurp
<Card /> is a
component; <card /> is a plain HTML element and is emitted as one. There is no
registration step beyond the using line.
Props are passed by expression
To pass a value, brace it. To build a string around a value, brace a template literal.Prop forms
Prop declarations and defaults
Theprops block records names and types for tooling. Types are never checked
at render time, so a missing prop is simply null and renders as the empty
string. No error, no warning.
Two things follow from that:
- An undeclared prop still arrives. Passing
<Card note={"hi"} />makesnotereadable inside the component even thoughpropsnever mentions it. Declaring it serves the reader and the editor, not the renderer. - A
= defaultdoes have a render-time effect. Omitfeaturedabove and the component seesfalse, not null. The default expression is evaluated in the caller’s scope, so it can read the caller’s globals.
Scope: page globals, overlaid by props
A component renders in its own root scope. It sees the page globals, with whatever was passed to it layered on top and winning on a name collision. So a component can read a global it was never passed:components/Footer.slurp
{each} loop variable and
loop.index do not exist inside a component.
loop.index works the same way. It is a caller-side value, so build the string
in the caller and pass the result:
Children and the slot
Children of a component tag land at its<slot />.
components/Badge.slurp
A component with no slot discards its children
A component with no slot discards its children
<NoSlot>children here</NoSlot> renders the component and drops the text.
Silently. If content vanishes, check that the component has a <slot />.There are no named slots
There are no named slots
A component has exactly one content slot.
<slot name="sidebar" /> renders
as a literal <slot> element carrying its fallback content, and a child
written <nav slot="sidebar"> is not routed to it: it lands in the default
slot with everything else. You get both copies, in the wrong place, with no
diagnostic.Anything that would have been a second slot becomes a prop, or its own
component. See Layouts and slots for the one exception,
which is the layout head slot.Passing a list
There is no special array prop. Pass the array and loop inside the component.components/List.slurp
any is the annotation when the element shape is not declared.
items: Product[] renders identically, because no annotation is ever enforced.
Importing
The
@ path is the file’s path from the input root with the extension dropped,
so components/ui/Button.slurp is @components/ui/Button. Nested directories
work. Relative paths such as "./components/Card" do not resolve on the CLI.
Imports are per file. A component that uses another component imports it itself;
it does not inherit the page’s imports.
components/Outer.slurp
When a component does not resolve
The same placeholder appears when a component includes itself. Recursion is stopped by a cycle guard rather than by an error, so<Recur /> renders one
level and then a placeholder.
Next
Layouts and slots
Layouts, slots, and the head block.
Displaying data
Expressions, property access, and operators.
Control flow
{if}, {each}, {match} and the loop variables.Common mistakes
The silent failures, collected in one place.