Content & media
Loops & conditions
Repeating a subtree over a query, and shipping something only when it should be there.
Two elements are logic rather than markup. Neither emits a tag of its own: a Loop emits Astro's .map(), a Condition emits a guard. They have no box and nothing to style — put a Div inside or around one when you want a box.
Loops
A loop repeats its children once per entry.
---
import items from '../data/projects.json';
---
{items.map((item) => (
<article builder-data-element="div" class="project-card">
<h3 builder-data-element="heading" class="project-card__title">{item.title}</h3>
<p builder-data-element="text">{item.year}</p>
</article>
))}The query is in the page's frontmatter, where anyone can read it. There is no runtime layer and no server-only mystery.
Three sources
| Source | Reads |
|---|---|
| Content type | a type from Content — its live rows, via src/data/<slug>.json |
| File | any .json in the project |
| Custom | data typed into the builder, or an expression you write |
Anything JSON can hold counts as a row. ["red", "blue"] is as good a list as a list of objects, and binds as the bare {item}.
Settings
- Item name — what the binding is called.
itemby default; name itprojectif that reads better. - How many — a limit.
- Sort by and direction.
- Where — a filter on a field.
Bindings
Inside the loop, {item.title} works in text and in attributes:
<a builder-data-element="link" href={'/projects/' + item.slug}>{item.title}</a>A binding that names something not actually in scope is emitted as literal text rather than as code — {item.x} visibly wrong in the page beats item is not defined failing the whole build.
On the canvas
A loop previews with the real rows, not a single placeholder. That is deliberate: laying out three cards is a different job from laying out one, and a builder that shows you one is hiding the job.
Conditions
A condition decides whether what is inside it reaches the page at all.
| Mode | Means |
|---|---|
| Frontend | ships, but is hidden in the builder — for a thing you do not want in the way while you work |
| Builder | never ships — notes, guides, a scratch block |
| Custom | emits {expr && (…)} with an expression of yours |
A custom condition is ordinary Astro: anything in scope on that page can decide.
A condition is not a display toggle. display: none is styling — it ships and is read by assistive technology. A condition removes the markup from the output.