Error State

Placeholder shown when something failed to load or submit — page-level errors, network retries, and form-level error summaries.

Page-level error

For a whole page or panel that failed to render. Pairs a clear cause-free message (the error wasn't the user's fault) with two ways forward: retry in place, or leave entirely. Always offer both — a retry-only error traps anyone hitting a hard failure.

500 — Something went wrong

The page failed to load on our end. It's not something you did — try again in a moment.

Go to homepage
<div class="hero bg-base-100 rounded-[var(--radius-sm)] py-16">
  <div class="hero-content text-center">
    <div class="max-w-sm">
      <i data-lucide="server-crash" class="mx-auto mb-4 size-12 text-error/60"></i>
      <h3 class="text-lg font-semibold">500 — Something went wrong</h3>
      <p class="py-3 text-base-content/60">
        The page failed to load on our end. It's not something you did —
        try again in a moment.
      </p>
      <div class="flex justify-center gap-2">
        <button class="btn btn-primary btn-sm">Try again</button>
        <a href="#" class="btn btn-ghost btn-sm">Go to homepage</a>
      </div>
    </div>
  </div>
</div>

Network error retry

Smaller footprint than the full page-level variant — for a widget, panel, or single request that failed inside an otherwise-working page. The retry button shows its own loading state so a slow connection doesn't read as a second failure.

Couldn't reach the server

Check your connection and try again.

<div class="text-center py-12 px-4">
  <i data-lucide="wifi-off" class="mx-auto mb-3 size-9 text-error/60"></i>
  <h3 class="font-semibold">Couldn't reach the server</h3>
  <p class="text-sm text-base-content/60 mt-1">
    Check your connection and try again.
  </p>
  <button class="btn btn-outline btn-error btn-sm mt-4">
    <i data-lucide="refresh-cw" class="size-4"></i>
    Retry
  </button>
</div>

Form-level error summary

Sits at the top of a form to list every validation failure at once, so a long form doesn't make the user hunt field-by-field for what's wrong. Uses DaisyUI's alert rather than a custom banner — severity-coded blocks are exactly what alert is for.

<div role="alert" class="alert alert-error alert-soft">
  <i data-lucide="circle-alert" class="size-5 shrink-0"></i>
  <div>
    <p class="font-medium">3 fields need your attention</p>
    <ul class="text-sm mt-1 list-disc list-inside opacity-90">
      <li>Email address is invalid</li>
      <li>Password must be at least 8 characters</li>
      <li>You must accept the terms to continue</li>
    </ul>
  </div>
</div>

Inline field error

The smallest unit of error state — attached directly to the input that failed. Uses DaisyUI's input-error modifier rather than a custom border color, so it stays in sync with whatever theme colors the builder is using.

<label class="form-control w-full max-w-xs">
  <span class="label-text mb-1">Email</span>
  <input type="email" value="not-an-email" class="input input-error w-full" />
  <span class="text-error text-xs mt-1 flex items-center gap-1">
    <i data-lucide="circle-alert" class="size-3.5"></i>
    Enter a valid email address
  </span>
</label>

Pick the variant that matches the failure's blast radius: a whole page that can't render needs the page-level variant with an escape route, a single failed request needs the smaller retry variant, and form problems belong with the form — either summarized at the top for long forms, or inline for a single field. Don't reach for the page-level variant just because an error "feels serious"; a failed save inside an otherwise-working page is still a small-footprint failure.