Meldung
Meldungen in der Seite für Info, Erfolg, Warnung und Fehler, jeweils mit Icon und klaren Worten. Die Töne kommen aus den Kit-Tokens.
Eine von 9 Components in Overlays
Details
Was Meldung mitbringt, aus Registry und Quellcode gelesen.
- Kategorie
- Overlays
- Bereich
- Elements
- Variants
- 2
- Version
- 1.0.0 · seit 1.0.0
- Datei
- components/ui/alert.tsx
- npm-Pakete
- Keine
- Sprachen
- Englisch und Deutsch, 1 eigener Text
- Studio
- Im Code anpassen
- Mit KI bauen
- Per MCP in Claude, Cursor, Copilot und Codex
Props
Die Schnittstelle AlertProps aus components/ui/alert.tsx. Beschreibungen stammen aus den Kommentaren im Code und sind auf Englisch.
toneoptionalAlertToneneutralinfosuccesswarningerror
titleoptionalReact.ReactNodechildrenoptionalReact.ReactNodeiconoptionalIconNameOverride the tone icon
actionsoptionalReact.ReactNodeButtons or links under the text (or at the end in the inline layout)
dismissibleoptionalbooleanShows a dismiss button. The alert hides itself and calls onDismiss.
onDismissoptional() => voidvariantoptional'soft' | 'outline' | 'accent' | 'inline'soft: tinted surface (default). outline: card with a colored icon. accent: a bar on the start edge. inline: one compact line.
Eingebaute Texte
Diese Texte schreibt Meldung selbst. Die Sprache folgt dem KitProvider, über die Prop labels ersetzt du einzelne.
Alle 1 Texte anzeigen
| Schlüssel | Englisch | Deutsch |
|---|---|---|
| dismiss | Englisch Dismiss | Deutsch Ausblenden |
Barrierefreiheit
Aus dem Quellcode der Component abgeleitet.
- Setzt aria-label, damit Screenreader Zweck und Zustand ansagen.
- Nutzt die Rollen alert, status und urgent.
- Meldet Änderungen über eine Live-Region, ohne den Fokus zu verschieben.
- Der Server rendert den Startzustand vollständig, JavaScript ergänzt nur die Interaktion.
Bewegung
- Bringt eigene Animationen mit, ruhig getaktet und ohne Wackeln.
- Bei reduzierter Bewegung (prefers-reduced-motion) bleibt sie ruhig. 2 Stellen im Code schalten Bewegung dann ab.
Quellcode
Die Datei, die aiw add in dein Projekt legt. Sie gehört danach dir.
Datei anzeigen, 141 Zeilen
'use client';
import { useRef, useState } from 'react';
import { cn, prefersReducedMotion, useInView, useTexts } from '@/lib/kit';
import { Icon, type IconName } from '@/components/ui/icon';
const TEXTS = { en: { dismiss: 'Dismiss' }, de: { dismiss: 'Ausblenden' } };
/* The icon pops in once the alert is in view */
const CSS =
'.kitfx-alert[data-in] .kitfx-alert-icon{animation:kitfx-alert-icon .6s cubic-bezier(.34,1.56,.64,1) .12s both}@keyframes kitfx-alert-icon{from{opacity:0;transform:scale(.5)}}' +
'@media (prefers-reduced-motion:reduce){.kitfx-alert .kitfx-alert-icon{animation:none}}';
export type AlertTone = 'neutral' | 'info' | 'success' | 'warning' | 'error';
/* One color per tone, everything else is mixed from it, so both modes and every accent stay in tune */
const TONE: Record<AlertTone, { color: string; icon: IconName }> = {
neutral: { color: 'var(--muted-foreground)', icon: 'info' },
info: { color: 'var(--info)', icon: 'info' },
success: { color: 'var(--success)', icon: 'check-circle' },
warning: { color: 'var(--warning)', icon: 'alert' },
error: { color: 'var(--destructive)', icon: 'alert-circle' },
};
export interface AlertProps {
tone?: AlertTone;
title?: React.ReactNode;
children?: React.ReactNode;
/** Override the tone icon */
icon?: IconName;
/** Buttons or links under the text (or at the end in the inline layout) */
actions?: React.ReactNode;
/** Shows a dismiss button. The alert hides itself and calls onDismiss. */
dismissible?: boolean;
onDismiss?: () => void;
/** soft: tinted surface (default). outline: card with a colored icon. accent: a bar on the start edge. inline: one compact line. */
variant?: 'soft' | 'outline' | 'accent' | 'inline';
labels?: Partial<(typeof TEXTS)['en']>;
className?: string;
}
/**
* A message in the flow of the page: info, success, warning or error. Always text and icon, never color alone.
* Errors and warnings use role="alert", the others role="status".
* <Alert tone="warning" title="Your trial ends in 3 days">Add a payment method to keep your projects.</Alert>
*/
export function Alert({ tone = 'info', title, children, icon, actions, dismissible, onDismiss, variant = 'soft', labels, className }: AlertProps) {
const t = useTexts(TEXTS, labels);
const [open, setOpen] = useState(true);
const [ref, inView] = useInView<HTMLDivElement>();
const leaving = useRef(false);
if (!open) return null;
const c = TONE[tone];
const urgent = tone === 'error' || tone === 'warning';
const ink = `color-mix(in oklab, ${c.color} 78%, var(--foreground))`;
const surface = {
soft: 'border border-[color-mix(in_oklab,var(--tone)_28%,var(--border))] bg-[color-mix(in_oklab,var(--tone)_8%,var(--background))]',
outline: 'border border-border bg-card shadow-[var(--highlight),var(--shadow-sm)]',
accent: 'border border-border border-s-[3px] border-s-[var(--tone)] bg-card shadow-[var(--shadow-sm)]',
inline: 'border border-[color-mix(in_oklab,var(--tone)_24%,var(--border))] bg-[color-mix(in_oklab,var(--tone)_7%,var(--background))]',
}[variant];
const dismiss = dismissible && (
<button
type="button"
aria-label={t.dismiss}
onClick={() => {
const el = ref.current;
const done = () => {
setOpen(false);
onDismiss?.();
};
if (!el || prefersReducedMotion()) return done();
if (leaving.current) return;
leaving.current = true;
// Out first, then the space closes, so the content below glides up instead of jumping
const h = el.offsetHeight;
el.style.pointerEvents = 'none';
el.style.overflow = 'hidden';
el.animate([{ opacity: 1, transform: 'none' }, { opacity: 0, transform: 'translateX(12px) scale(0.98)' }], { duration: 220, easing: 'cubic-bezier(0.4, 0, 0.9, 0.6)', fill: 'forwards' })
.finished.then(() => el.animate([{ height: `${h}px`, marginBlock: getComputedStyle(el).marginBlock }, { height: '0px', marginBlock: '0px', paddingBlock: '0px', borderWidth: '0px' }], { duration: 240, easing: 'cubic-bezier(0.2, 0.7, 0.2, 1)', fill: 'forwards' }).finished)
.then(done, done);
}}
className={cn('group/close grid size-8 shrink-0 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-[color-mix(in_oklab,var(--tone)_12%,transparent)] hover:text-foreground', variant !== 'inline' && '-me-1.5 -mt-1.5')}
>
<Icon name="x" size={15} className="transition-transform duration-300 ease-[var(--ease-kit)] group-hover/close:rotate-90 motion-reduce:transition-none" />
</button>
);
// Rises into place when it scrolls into view, the icon pops
const motion = cn('kitfx-alert transition-[opacity,translate] duration-700 ease-[var(--ease-kit)] motion-reduce:transition-none', !inView && 'translate-y-3 opacity-0');
const style = <style href="kitfx-alert" precedence="default">{CSS}</style>;
if (variant === 'inline') {
return (
<div ref={ref} data-in={inView || undefined} role={urgent ? 'alert' : 'status'} className={cn('flex min-h-11 items-center gap-2.5 rounded-lg px-3 py-2 text-sm', surface, motion, className)} style={{ '--tone': c.color } as React.CSSProperties}>
{style}
<Icon name={icon ?? c.icon} size={16} className="kitfx-alert-icon shrink-0" style={{ color: ink }} />
<p className="min-w-0 flex-1 text-pretty text-foreground">
{title && <span className="font-medium">{title} </span>}
<span className="text-muted-foreground">{children}</span>
</p>
{actions && <div className="flex shrink-0 items-center gap-2 text-[13px] font-medium">{actions}</div>}
{dismiss}
</div>
);
}
return (
<div ref={ref} data-in={inView || undefined} role={urgent ? 'alert' : 'status'} className={cn('relative flex gap-3 rounded-xl p-4', surface, motion, className)} style={{ '--tone': c.color } as React.CSSProperties}>
{style}
<span
className={cn('kitfx-alert-icon grid shrink-0 place-items-center', variant === 'outline' ? 'size-8 rounded-lg bg-[color-mix(in_oklab,var(--tone)_12%,transparent)]' : 'size-5 mt-px')}
style={{ color: ink }}
>
<Icon name={icon ?? c.icon} size={variant === 'outline' ? 17 : 18} />
</span>
<div className={cn('min-w-0 flex-1', variant === 'outline' && 'pt-[5px]')}>
{title && <p className="text-sm font-semibold leading-5 text-foreground">{title}</p>}
{children && <div className={cn('text-pretty text-sm leading-relaxed text-muted-foreground', title && 'mt-1')}>{children}</div>}
{actions && <div className="mt-3 flex flex-wrap items-center gap-x-4 gap-y-2 text-[13px] font-medium">{actions}</div>}
</div>
{dismiss}
</div>
);
}
/** A text link styled for alert actions */
export function AlertLink({ href, onClick, children }: { href?: string; onClick?: () => void; children: React.ReactNode }) {
const cls = 'inline-flex items-center gap-1 text-foreground underline decoration-[color-mix(in_oklab,var(--tone,var(--foreground))_45%,transparent)] underline-offset-4 transition-[text-decoration-color] duration-200 hover:decoration-current';
return href ? (
<a href={href} className={cls}>
{children}
</a>
) : (
<button type="button" onClick={onClick} className={cls}>
{children}
</button>
);
}Häufige Fragen
Wie installiere ich Meldung?
Mit aiw add @ai-website/alert. Der Befehl legt die Datei components/ui/alert.tsx in dein Projekt, der Code gehört danach dir. Mit dabei sind icon und toast. Weitere npm-Pakete braucht sie nicht.
Welche Varianten hat Meldung?
2 Varianten, Töne und Stile.
Kann ich die Texte von Meldung übersetzen?
Ja. Meldung bringt 1 eigene Texte auf Deutsch und Englisch mit, etwa „Ausblenden“. Die Sprache folgt dem KitProvider, einzelne Texte ersetzt du über die Prop labels.
Kann ein KI-Assistent Meldung einbauen?
Ja. Über den MCP-Server der aiw CLI finden Claude, Cursor, GitHub Copilot, Windsurf, Codex und Gemini Meldung mit aiw_components und installieren sie mit aiw_add @ai-website/alert. Nenn im Prompt die Variante, etwa variant="outline|accent|inline", dann schreibt der Assistent deine Inhalte direkt in die Props.