Skip to content

Styling in Astro

In React you reach for CSS Modules, styled-components, emotion, or Tailwind. You wire up global CSS through _app.tsx or a layout component. Class toggling means clsx(...) or a ternary on className.

Astro keeps the same CSS you already know — no new syntax to learn. What changes is where styles live and how they are scoped. A <style> block inside a .astro file is automatically scoped to that component by the compiler. Global CSS comes in through <style is:global> or a stylesheet import. And Tailwind works exactly as it does in Next, once you add the integration.

This module walks through each approach anchored to what you already know from React.

LessonWhat you will learn
Scoped Styles<style> auto-scoped vs CSS Modules
Global Stylesis:global and stylesheet imports vs _app.tsx
CSS Variables and class:listdefine:vars and class:list vs clsx / inline styles
TailwindAdding Tailwind to Astro vs Tailwind in Next
React
// Card.jsx (CSS Modules)
import styles from './Card.module.css';
import clsx from 'clsx';
export default function Card({ title, featured }) {
return (
<div className={clsx(styles.card, featured && styles.featured)}>
<h2 className={styles.title}>{title}</h2>
</div>
);
}
Astro
---
// Card.astro
const { title, featured } = Astro.props;
---
<div class:list={["card", { featured }]}>
<h2 class="title">{title}</h2>
</div>
<style>
.card { border: 1px solid #e2e8f0; border-radius: 8px; padding: 1rem; }
.title { font-size: 1.25rem; margin: 0; }
.featured { border-color: #6366f1; background: #eef2ff; }
</style>

Notice what disappears: no CSS Module import, no clsx import, no .module.css file. The <style> block travels with the component and the compiler handles scoping automatically.

Astro
---
const title = "Astro Styling Overview";
const featured = true;
---
<html lang="en">
  <head><meta charset="utf-8" /><title>Styling</title></head>
  <body>
    <div class:list={["card", { featured }]}>
      <h2 class="title">{title}</h2>
      <p>Styles are scoped to this component automatically.</p>
    </div>
  </body>
</html>

<style>
  body { font-family: sans-serif; padding: 2rem; background: #f8fafc; }
  .card { border: 2px solid #e2e8f0; border-radius: 8px; padding: 1.5rem; max-width: 360px; }
  .title { font-size: 1.4rem; margin: 0 0 .5rem; }
  .featured { border-color: #6366f1; background: #eef2ff; }
</style>
What happens to a plain `<style>` block inside a .astro file by default?
What is the Astro equivalent of `clsx(styles.card, active && styles.active)`?
How do you apply styles globally in an Astro component?