Zum Inhalt springen
UI Kit
Accent

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

2 Variants

Variants

Töne

Weiche Flächen mit Titel, Text und Aktionen. Sie steigen nacheinander auf, eine ausgeblendete Meldung gleitet hinaus und der Platz schließt sich weich.

Stile

Umrandet für Karten, ein Balken an der Kante für lange Seiten, eine kompakte Zeile für Formulare und Leisten.

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
Bringt mit
utilskiticontoast
npm-Pakete
Keine
Sprachen
Englisch und Deutsch, 1 eigener Text
Studio
Im Code anpassen

Props

Die Schnittstelle AlertProps aus components/ui/alert.tsx. Beschreibungen stammen aus den Kommentaren im Code und sind auf Englisch.

  • toneoptional
    AlertTone

    neutralinfosuccesswarningerror

  • titleoptional
    React.ReactNode
  • childrenoptional
    React.ReactNode
  • iconoptional
    IconName

    Override the tone icon

  • actionsoptional
    React.ReactNode

    Buttons or links under the text (or at the end in the inline layout)

  • dismissibleoptional
    boolean

    Shows a dismiss button. The alert hides itself and calls onDismiss.

  • onDismissoptional
    () => void
  • variantoptional
    '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
dismissEnglisch DismissDeutsch 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
components/ui/alert.tsx
'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.

Oft gesucht

Direkt zu

In die Zwischenablage kopiert