komal.nakrani
Browse Themes
ThemesCategoriesDocsBlogTips & Tricks
Components & Islands••By Komal Nakrani

Conditional Rendering in Astro

Conditional rendering in Astro uses JavaScript expressions in the template: && for show/hide, ternaries for either/or, and early variables for complex cases.

#Astro#Components#Templates

Conditional rendering in Astro works the same way as in JSX: write a JavaScript expression inside curly braces in the template. Use {condition && <Element />} to show something only when a condition is true, and {condition ? <A /> : <B />} to choose between two things. There is no v-if or {#if} block syntax.

Key Takeaways

  • && shows or hides; a ternary chooses between two branches.
  • Move complex logic into the frontmatter and render a variable.
  • Watch out for 0 && ..., which renders a literal 0.
  • Conditions run on the server, at build or request time, not in the browser.

Show or hide with &&

---
const { title, subtitle, isNew = false } = Astro.props;
---
<h2>
  {title}
  {isNew && <span class="badge">New</span>}
</h2>
{subtitle && <p class="subtitle">{subtitle}</p>}

If subtitle is an empty string or undefined, nothing renders.

The zero trap

&& returns its left side when that side is falsy. For 0, that means a 0 appears on the page:

{/* Renders "0" when there are no comments */}
{comments.length && <p>{comments.length} comments</p>}

{/* Correct */}
{comments.length > 0 && <p>{comments.length} comments</p>}

Always compare numbers explicitly.

Either/or with a ternary

---
const user = Astro.locals.user;
---
{user
  ? <a href="/account/">Hi, {user.name}</a>
  : <a href="/login/">Sign in</a>}

Nested ternaries get hard to read quickly. Past two branches, use the next pattern.

Complex conditions in the frontmatter

Decide in the script, render a single value in the template:

---
import InfoIcon from './icons/Info.astro';
import WarningIcon from './icons/Warning.astro';
import ErrorIcon from './icons/Error.astro';

interface Props { type: 'info' | 'warning' | 'error' }
const { type } = Astro.props;

const icons = { info: InfoIcon, warning: WarningIcon, error: ErrorIcon };
const Icon = icons[type];
---
<div class:list={['alert', `alert-${type}`]}>
  <Icon />
  <slot />
</div>

Assigning a component to a capitalised variable and rendering <Icon /> is a dynamic component. It avoids a chain of conditions in the template entirely.

Dynamic tags

The same trick works for HTML elements. A heading component that renders the right level:

---
interface Props { level?: 1 | 2 | 3 | 4 }
const { level = 2 } = Astro.props;
const Tag = `h${level}`;
---
<Tag class="heading"><slot /></Tag>

Note that a dynamic tag variable can’t be used for a component with a client:* directive; hydration needs a static import.

Conditional attributes and classes

Attributes set to false, null or undefined are omitted:

<a href={href} target={external ? '_blank' : undefined} rel={external ? 'noopener' : undefined}>
  <slot />
</a>

For classes, class:list handles conditions cleanly (the Astro styling guide has more on combining it with Tailwind):

<li class:list={['nav-item', { active: Astro.url.pathname === href }]}>

Conditional slots

Render a wrapper only when a slot was filled:

{Astro.slots.has('footer') && (
  <footer class="card-footer"><slot name="footer" /></footer>
)}

Without the check, you’d get an empty <footer> element with its padding and border.

Remember: this runs on the server

Template conditions are evaluated when the page renders, at build time for static pages. A condition based on window.innerWidth or localStorage won’t work here; that belongs in a <script> tag or an island. For responsive show/hide, CSS media queries are usually the right tool.

For props, slots and dynamic components in depth, read the Astro components guide. If you need to render a raw HTML string conditionally, see Fragment and set:html. The Astro template syntax reference has the full rules.

FAQ

Does Astro have an if statement in templates?

No. Use JavaScript expressions: && for show/hide and the ternary operator for either/or. For complex logic, compute a value in the frontmatter.

Why does my Astro template show a 0?

You used {count && ...} with count equal to 0. Write {count > 0 && ...} instead.