Menu

Change language

GitHub repo

404 Not Found

blocklayout

Full-page 404 with an isometric missing-page illustration, HTTP code, headline, and Back to home + Contact support. Prop-driven: pass title, description, image, action labels, hrefs, and layout (`page` | `contained`). Pass `image=""` to hide the art.

Installation

$npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/error-404.json
Manifest:https://uipkge.dev/r/svelte/error-404.jsonInstalls to:src/lib/components/blocks/error-404/

Variants

Loading interactive previews…

npm dependencies

Includes

Files installed (1)

  • src/lib/components/blocks/error-404/Error404.svelte4.6 kB
    <script lang="ts" module>
      import type { Component } from 'svelte'
    
      export interface Error404Props {
        code?: string
        title?: string
        description?: string
        /** Replaces the HTTP response panel. Pass `''` to hide art entirely. */
        image?: string
        imageAlt?: string
        primaryLabel?: string
        secondaryLabel?: string
        primaryHref?: string
        secondaryHref?: string
        showPrimary?: boolean
        showSecondary?: boolean
        primaryDisabled?: boolean
        secondaryDisabled?: boolean
        onPrimary?: () => void
        onSecondary?: () => void
        /** `'page'` fills the viewport; `'contained'` fits a preview or nested panel. */
        layout?: 'page' | 'contained'
        class?: string
      }
    </script>
    
    <script lang="ts">
      import { ArrowLeft, LifeBuoy } from '@lucide/svelte'
      import { cn } from '$lib/utils'
      import { Button, buttonVariants, type ButtonVariants } from '$lib/components/ui/button'
    
      let {
        code: codeOverride,
        title: titleOverride,
        description: descriptionOverride,
        image = '/illustrations/error-404.jpg',
        imageAlt = '',
        primaryLabel: primaryLabelOverride,
        secondaryLabel: secondaryLabelOverride,
        primaryHref,
        secondaryHref,
        showPrimary = true,
        showSecondary = true,
        primaryDisabled = false,
        secondaryDisabled = false,
        onPrimary,
        onSecondary,
        layout = 'page',
        class: className,
      }: Error404Props = $props()
    
      const copy = (fallback: string, override?: string) => (override === undefined ? fallback : override)
    
      const code = $derived(copy('404', codeOverride))
      const title = $derived(copy('Page not found', titleOverride))
      const description = $derived(
        copy(
          "The page you're looking for doesn't exist or may have been moved. Check the URL or head back home.",
          descriptionOverride,
        ),
      )
      const primaryLabel = $derived(copy('Back to home', primaryLabelOverride))
      const secondaryLabel = $derived(copy('Contact support', secondaryLabelOverride))
    </script>
    
    {#snippet actionButton(
      href: string | undefined,
      label: string,
      variant: ButtonVariants['variant'] = 'default',
      disabled = false,
      onclick?: () => void,
      Icon?: Component,
    )}
      {#if href}
        <a {href} class={buttonVariants({ variant, size: 'lg' })} {onclick} aria-disabled={disabled}>
          {#if Icon}
            <Icon />
          {/if}
          {label}
        </a>
      {:else}
        <Button {variant} size="lg" {disabled} {onclick}>
          {#if Icon}
            <Icon />
          {/if}
          {label}
        </Button>
      {/if}
    {/snippet}
    
    <section
      data-slot="error-404"
      data-layout={layout}
      class={cn(
        'bg-background relative flex items-center overflow-hidden px-6 py-16',
        layout === 'page' ? 'min-h-svh' : 'min-h-[28rem]',
        className,
      )}
    >
      <div class="mx-auto grid w-full max-w-5xl items-center gap-10 lg:grid-cols-2 lg:gap-16">
        <div>
          {#if code}
            <p class="text-muted-foreground text-sm font-medium">HTTP {code}</p>
          {/if}
          {#if code}
            <p class="mt-3 text-6xl font-semibold tracking-tighter sm:text-7xl">{code}</p>
          {/if}
          <h1 class="mt-3 text-2xl font-semibold tracking-tight sm:text-3xl">{title}</h1>
          {#if description}
            <p class="text-muted-foreground mt-4 max-w-md text-base">{description}</p>
          {/if}
          {#if showPrimary || showSecondary}
            <div class="mt-8 flex flex-wrap items-center gap-3">
              {#if showPrimary}
                {@render actionButton(primaryHref, primaryLabel, 'default', primaryDisabled, onPrimary, ArrowLeft)}
              {/if}
              {#if showSecondary}
                {@render actionButton(secondaryHref, secondaryLabel, 'outline', secondaryDisabled, onSecondary, LifeBuoy)}
              {/if}
            </div>
          {/if}
        </div>
        {#if image}
          <div class="border-border bg-muted overflow-hidden rounded-xl border">
            <img src={image} alt={imageAlt} class="aspect-[4/3] w-full object-cover" />
          </div>
        {:else if image === undefined}
          <div
            class="border-border bg-muted/40 overflow-hidden rounded-xl border font-mono"
            aria-hidden="true"
          >
            <div class="border-border text-muted-foreground truncate border-b px-3 py-2 text-xs">
              curl -i https://app.acme.dev/pricing/teams
            </div>
            <div class="space-y-1 p-4 text-xs leading-relaxed">
              <p><span class="text-muted-foreground">HTTP/1.1</span> {code || '404'} Not Found</p>
              <p class="text-muted-foreground">content-type: application/json</p>
              <p class="text-muted-foreground">x-request-id: req_9k2e18</p>
              <p class="text-muted-foreground mt-3">{'{ "error": "not_found", "path": "/pricing/teams" }'}</p>
            </div>
          </div>
        {/if}
      </div>
    </section>
    

Raw manifest:https://uipkge.dev/r/svelte/error-404.json