Component Basics
Grundlagen der Component-Entwicklung für Webmate Studio.
Component-Struktur
Jede Component ist ein Verzeichnis mit diesen Dateien:
components/
└── MyComponent/
├── component.html # Erforderlich: HTML Template
├── islands/ # Optional: Interactive JavaScript
│ └── my-component.js
└── assets/ # Optional: Bilder, Fonts, etc.
└── image.jpgMinimale Component
Die einfachste mögliche Component:
Verzeichnis: components/SimpleText/
component.html:
<div class="simple-text">
<p class="text-gray-600">Hello World</p>
</div>Das ist alles! Keine Build-Config, kein Framework-Overhead, nur HTML.
component.html
Das HTML-Template mit deinem Markup:
Basis-Struktur
<div class="component-wrapper">
<h2 class="text-2xl font-bold text-gray-900">{{title}}</h2>
<p class="text-gray-600">{{description}}</p>
</div>
<style>
/* Optional: Custom CSS */
.component-wrapper {
/* Deine Styles hier */
}
</style>Props verwenden
Props werden über wm dev verwaltet und mit interpoliert:
<h1>{{title}}</h1>
<p>{{subtitle}}</p>
<img src="{{imageUrl}}" alt="{{imageAlt}}">Mehr dazu: Props
Conditionals
Elemente bedingt anzeigen mit wm:if:
<img wm:if="showImage" src="{{imageUrl}}" alt="Hero">
<div wm:if="!showImage" class="placeholder"></div>Mehr dazu: Conditionals
Loops
Listen rendern mit wm:for:
<ul>
<li wm:for="item in items">
{{item.name}}
</li>
</ul>Mehr dazu: Loops
Keine Script Tags!
❌ Nicht so:
<div id="my-component"></div>
<script>
// Funktioniert nicht!
document.getElementById('my-component').innerHTML = 'Hello';
</script>✅ Sondern so:
Verwende Islands für JavaScript:
<!-- component.html -->
<div data-island="my-component">
<!-- Island übernimmt hier -->
</div>// islands/my-component.js
export default class MyComponentIsland {
constructor(element) {
element.innerHTML = 'Hello';
}
}Warum keine Scripts?
- Sicherheit: Scripts können nicht sanitized werden
- SSR: Server-side Rendering führt
<script>nicht aus - Islands: Proper Lifecycle-Management
- Performance: Islands laden nur bei Bedarf
Tailwind CSS verwenden
Alle Components haben Zugriff auf Tailwind Utility Classes:
Layout
<div class="container mx-auto px-4 py-8">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="col-span-1">Column 1</div>
<div class="col-span-1">Column 2</div>
<div class="col-span-1">Column 3</div>
</div>
</div>Typography
<h1 class="text-4xl font-bold text-gray-900 mb-4">Heading 1</h1>
<h2 class="text-3xl font-semibold text-gray-800 mb-3">Heading 2</h2>
<p class="text-base text-gray-600 leading-relaxed">Body text with good line height.</p>
<a href="#" class="text-blue-600 hover:text-blue-800 underline">Link</a>Colors
<!-- Standard colors -->
<div class="bg-blue-600 text-white">Blue background</div>
<div class="bg-red-500 text-white">Red background</div>
<div class="bg-green-600 text-white">Green background</div>
<!-- Design Tokens (konfiguriert im CMS) -->
<div class="bg-primary text-white">Primary color</div>
<div class="bg-secondary text-white">Secondary color</div>Design Tokens
text-primary, bg-primary, border-primary verwenden Farben aus den CMS-Einstellungen. Admins können diese ändern, ohne Components anzupassen.
Mehr: Design Tokens
Spacing
<!-- Padding -->
<div class="p-4">Padding all sides (1rem)</div>
<div class="px-6 py-4">Padding horizontal & vertical</div>
<div class="pt-8 pb-4">Padding top & bottom</div>
<!-- Margin -->
<div class="m-4">Margin all sides</div>
<div class="mt-8 mb-4">Margin top & bottom</div>
<div class="mx-auto">Center with auto margins</div>
<!-- Gaps (for flex/grid) -->
<div class="flex gap-4">
<div>Item 1</div>
<div>Item 2</div>
</div>Responsive Design
<div class="
w-full <!-- Mobile: full width -->
md:w-1/2 <!-- Tablet: 50% width -->
lg:w-1/3 <!-- Desktop: 33% width -->
xl:w-1/4 <!-- Large: 25% width -->
">
Responsive width
</div>
<div class="
text-sm <!-- Mobile: small text -->
md:text-base <!-- Tablet: normal text -->
lg:text-lg <!-- Desktop: large text -->
">
Responsive text
</div>Hover, Focus, Active States
<button class="
bg-blue-600
hover:bg-blue-700 <!-- Darker on hover -->
active:bg-blue-800 <!-- Even darker when clicked -->
focus:ring-2 <!-- Ring on focus -->
focus:ring-blue-500
focus:ring-offset-2
transition-colors <!-- Smooth color transitions -->
duration-200
">
Interactive Button
</button>Custom CSS
Für komplexere Styles verwende <style> Blöcke:
<div class="hero">
<h1 class="gradient-heading">{{title}}</h1>
</div>
<style>
.gradient-heading {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.hero {
animation: fadeIn 0.6s ease-out;
}
</style>Wann Custom CSS verwenden?
- ✅ Komplexe Gradients
- ✅ Custom Animations
- ✅ Pseudo-Elemente (::before, ::after)
- ✅ Komplexe Selektoren
- ❌ Einfache Farben, Padding, Margins (→ Tailwind)
- ❌ Basic Layouts (→ Tailwind Grid/Flex)
Islands (Interaktivität)
Islands fügen JavaScript-Interaktivität hinzu:
Wann Islands verwenden?
Verwende Islands für:
- ✅ Formulare mit Validierung
- ✅ Image Carousels
- ✅ Dropdowns, Modals
- ✅ Dynamisches Laden von Daten
- ✅ User-Interaktionen
Nicht verwenden für:
- ❌ Statischer Text
- ❌ Bilder
- ❌ Links
- ❌ Reine CSS-Animationen
Island hinzufügen
1. Island-File erstellen:
// islands/contact-form.js
export default class ContactFormIsland {
constructor(element, props = {}) {
this.element = element;
this.init();
}
init() {
// Island-Logic hier
}
destroy() {
// Cleanup
}
}2. In component.html verwenden:
<div
data-island="contact-form"
data-island-props='{"title": "{{title}}"}'
>
<!-- Island rendert hier -->
</div>Mehr: Islands Architecture
Workflow
Component erstellen
wm generate
# Oder kurz:
wm gInteraktiver Wizard führt dich durch:
- Component-Name
- Props
- Island-Framework (optional)
Testen
wm devPreview-Server auf localhost:5173
Hochladen
wm login # Einmalig
wm push # Upload zum CMSBest Practices
1. Fokussierte Components
❌ Schlecht: Eine Component für alles
MegaComponent/ (50 props, 1000+ Zeilen)✅ Gut: Kleine, fokussierte Components
Hero/, Features/, Testimonials/, CallToAction/2. Semantisches HTML
<!-- ✅ Gut -->
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
</header>
<!-- ❌ Divs für alles -->
<div class="header">
<div class="nav">...</div>
</div>3. Mobile-First
<div class="
text-base <!-- Mobile -->
md:text-lg <!-- Tablet -->
lg:text-xl <!-- Desktop -->
">
Responsive
</div>4. Accessibility
<!-- Alt-Text für Bilder -->
<img src="{{imageUrl}}" alt="{{imageAlt}}">
<!-- Beschreibende Link-Texte -->
<a href="/about">Mehr über uns erfahren</a>
<!-- Labels für Inputs -->
<label for="email">E-Mail</label>
<input id="email" type="email">5. Performance
<!-- Lazy Loading -->
<img src="{{imageUrl}}" loading="lazy" alt="{{title}}">
<!-- Islands nur wo nötig -->
<!-- ✓ Für Interaktivität -->
<div data-island="contact-form"></div>
<!-- ✗ Nicht für statischen Content -->
<div data-island="static-text">Text</div>Nächste Schritte
- Props - Dynamische Daten
- Conditionals - Bedingte Anzeige
- Loops - Listen rendern
- Design Tokens - CMS-Farben nutzen
- Tailwind CSS - Styling
- Islands - Interaktivität