Webdesign 14 Min. Lesezeit

Atomic Design in Astro: Atoms, Molecules & Organisms in der Praxis

Die Atomic Design Methodik konsequent in Astro umsetzen: Hierarchie-Regeln, Import-Grenzen, Slot-Komposition und häufige Fallstricke beim Aufbau eines Komponentensystems.

Atomic Design ist mehr als eine Ordner-Konvention — es ist eine Denk-Architektur, die vorgibt, welche Komponente von welcher anderen abhängen darf. Brad Frosts Konzept aus 2013 ist für Astro besonders gut geeignet, weil Astro-Komponenten keine Laufzeit-Dependencies haben — Fehler in der Hierarchie fallen sofort beim Build auf, nicht erst im Browser.

Die fünf Ebenen und ihre Grenzen

Atomic Design definiert fünf Ebenen:

EbeneBeispieleImportiert
AtomsButton, Input, Icon, Badge, HeadingNichts außer Design-Tokens
MoleculesSearchBar, FormField, NavLink, ArticleCardNur Atoms
OrganismsHeader, Footer, Hero, ContactFormMolecules (selten Atoms direkt)
TemplatesBaseLayout, BlogLayoutOrganisms
Pagesindex.astro, blog/[slug].astroTemplates + Organisms

Die wichtigste Regel: niemals aufwärts importieren. Ein Atom darf keine Molecule kennen. Eine Molecule darf keine Organism kennen.

src/
├── components/
│   ├── atoms/
│   │   ├── Button.astro
│   │   ├── Badge.astro
│   │   ├── Icon.astro
│   │   └── Heading.astro
│   ├── molecules/
│   │   ├── ArticleCard.astro
│   │   ├── NavLink.astro
│   │   └── PageHeader.astro
│   ├── organisms/
│   │   ├── Navigation.astro
│   │   ├── ServiceHero.astro
│   │   └── Footer.astro
│   └── seo/
│       └── SchemaArticle.astro
├── layouts/
│   └── Layout.astro
└── pages/

Atoms: maximal isoliert

Ein Atom ist die kleinste wiederverwendbare Einheit. Es hat keine Knowledge über seinen Kontext — es weiß nicht, ob es in einem Header oder einem Footer gerendert wird.

---
// components/atoms/Button.astro
interface Props {
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  as?: 'button' | 'a';
  href?: string;
  type?: 'button' | 'submit' | 'reset';
  disabled?: boolean;
  class?: string;
}

const {
  variant = 'primary',
  size = 'md',
  as: Tag = 'button',
  type = 'button',
  disabled = false,
  class: className = '',
  ...rest
} = Astro.props;

const variantClasses = {
  primary: 'bg-primary-600 hover:bg-primary-700 text-white',
  secondary: 'bg-white hover:bg-gray-50 text-primary-600 border border-primary-200',
  ghost: 'bg-transparent hover:bg-gray-100 text-gray-700',
};

const sizeClasses = {
  sm: 'px-3 py-1.5 text-sm',
  md: 'px-5 py-2.5 text-base',
  lg: 'px-8 py-4 text-lg',
};
---

<Tag
  class:list={[
    'inline-flex items-center justify-center gap-2 font-semibold rounded-lg transition-colors duration-200',
    variantClasses[variant],
    sizeClasses[size],
    disabled && 'opacity-50 cursor-not-allowed',
    className,
  ]}
  {type}
  {disabled}
  {...rest}
>
  <slot />
</Tag>

Wichtig: Das Button-Atom importiert nichts aus dem Komponentensystem. Es kennt nur Design-Tokens über Tailwind-Klassen.

Molecules: Atoms zusammenführen

Eine Molecule kombiniert Atoms zu einer kleinen, in sich geschlossenen Einheit, die eine spezifische Funktion erfüllt.

---
// components/molecules/ArticleCard.astro
import Badge from '../atoms/Badge.astro';

interface Props {
  title: string;
  description: string;
  slug: string;
  category: string;
  pubDate: Date;
  readingTime: number;
  categoryColor?: string;
}

const {
  title,
  description,
  slug,
  category,
  pubDate,
  readingTime,
  categoryColor = 'bg-gray-100 text-gray-700',
} = Astro.props;

function formatDate(date: Date): string {
  return date.toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' });
}
---

<article class="group bg-white dark:bg-gray-800 rounded-xl p-6 hover:shadow-md transition-shadow duration-300">
  <div class="flex items-center gap-2 mb-3">
    <Badge text={category} class={categoryColor} />
  </div>
  <h3 class="text-base font-semibold text-gray-900 dark:text-white mb-2
    group-hover:text-primary-600 dark:group-hover:text-primary-400
    transition-colors line-clamp-2">
    <a href={`/blog/${slug}/`} class="hover:underline">{title}</a>
  </h3>
  <p class="text-sm text-gray-600 dark:text-gray-400 mb-4 line-clamp-2">{description}</p>
  <div class="flex items-center justify-between text-sm text-gray-500 dark:text-gray-400">
    <span>{formatDate(pubDate)}</span>
    <span>{readingTime} Min. Lesezeit</span>
  </div>
</article>

Die ArticleCard-Molecule importiert nur Badge (ein Atom) — nicht andere Molecules oder Organisms.

Organisms: Molecules zur Sektion zusammenführen

---
// components/organisms/ServiceHero.astro
import Button from '../atoms/Button.astro';
import Badge from '../atoms/Badge.astro';

interface Props {
  badge?: string;
  title: string;
  description: string;
  ctaText: string;
  ctaHref: string;
  secondaryCtaText?: string;
  secondaryCtaHref?: string;
}

const {
  badge,
  title,
  description,
  ctaText,
  ctaHref,
  secondaryCtaText,
  secondaryCtaHref,
} = Astro.props;
---

<section class="relative py-20 md:py-32 bg-linear-to-br from-primary-50 to-white dark:from-gray-900 dark:to-gray-800 overflow-hidden">
  <div class="container">
    <div class="max-w-3xl mx-auto text-center">
      {badge && <Badge text={badge} class="mb-6 inline-flex" />}
      <h1 class="text-display-1 text-gray-900 dark:text-white mb-6">{title}</h1>
      <p class="text-body-lg text-gray-600 dark:text-gray-300 mb-8">{description}</p>
      <div class="flex flex-wrap items-center justify-center gap-4">
        <Button as="a" href={ctaHref} variant="primary" size="lg">
          {ctaText}
        </Button>
        {secondaryCtaText && secondaryCtaHref && (
          <Button as="a" href={secondaryCtaHref} variant="secondary" size="lg">
            {secondaryCtaText}
          </Button>
        )}
      </div>
    </div>
  </div>
</section>

Slots: flexible Komposition ohne Prop-Drilling

Astro-Slots sind das Haupt-Kompositions-Werkzeug. Sie ermöglichen es, Inhalte von außen in eine Komponente zu injizieren, ohne dass die Komponente den konkreten Inhalt kennen muss.

---
// components/molecules/Card.astro
---
<article class="bg-white dark:bg-gray-800 rounded-xl p-6 shadow-sm">
  <header class="mb-4">
    <slot name="header" />
  </header>
  <div class="prose prose-sm dark:prose-invert">
    <slot />
  </div>
  {Astro.slots.has('footer') && (
    <footer class="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700">
      <slot name="footer" />
    </footer>
  )}
</article>

Nutzung:

<Card>
  <Badge slot="header" text="BFSG" class="bg-purple-100 text-purple-700" />
  <p>BFSG verpflichtet Unternehmen zur technischen Barrierefreiheit.</p>
  <a slot="footer" href="/blog/bfsg-technische-umsetzung-astro/">Mehr erfahren</a>
</Card>

Häufige Fallstricke

1. Organisms mit zu viel Eigenlogik

Wenn ein Organism Datenbankabfragen oder API-Calls enthält, verliert er seine Wiederverwendbarkeit. Daten gehören in die Page oder ein Layout:

---
// pages/blog/index.astro — Daten kommen von hier
import { getPublishedArticles } from '../../data/blog-articles';
import ArticleGrid from '../../components/organisms/ArticleGrid.astro';

const articles = getPublishedArticles();
---

<ArticleGrid articles={articles} />
---
// components/organisms/ArticleGrid.astro — nur Rendering, keine Daten-Logik
interface Props {
  articles: BlogArticle[];
}
---

2. Atoms mit Routing-Logik

Ein Atom wie Button sollte nicht wissen, welche Routen existieren. Routen-spezifische Links gehören in Molecules oder direkt in die Page.

3. Inline-Stile in Atoms

Kein Atom sollte Inline-Stile (style="...") oder hardcodierte Hex-Farben enthalten. Ausschließlich Design-Tokens über Tailwind-Klassen.

Der “Golden Rule”-Test

Wenn man ein Atom ändert — z.B. den Button-Radius vergrößert — muss sich die Änderung auf alle Molecules, Organisms und Pages auswirken, die diesen Button verwenden. Wenn das nicht passiert, hat man keine echte Atomic Design Architektur — man hat nur Ordner.

Der Test: ändere ein Atom und prüfe via grep -r "components/atoms/Button", wie viele Dateien betroffen sind. Alle diese Stellen sollten die Änderung automatisch reflektieren.

Weiterführende Artikel


Komponentensystem für Ihr Projekt? Wender Media baut skalierbare Astro-Architekturen mit vollständiger Atomic Design Struktur — info@wendermedia.info.

Individuelle Beratung gewünscht?

Wender Media unterstützt Sie bei der praktischen Umsetzung — von der technischen Konzeption bis zum Launch. Schreiben Sie uns, wir antworten innerhalb von 24 Stunden.

Jetzt Beratung anfragen

Kostenlos & unverbindlich — info@wendermedia.info

Verwandte Artikel