404 Not Found
blocklayoutFull-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
$pnpm dlx shadcn@latest add https://uipkge.dev/r/lit/error-404.json$npx shadcn@latest add https://uipkge.dev/r/lit/error-404.json$yarn dlx shadcn@latest add https://uipkge.dev/r/lit/error-404.json$bunx shadcn@latest add https://uipkge.dev/r/lit/error-404.jsonManifest:
https://uipkge.dev/r/lit/error-404.jsonInstalls to:src/uip/blocks/error-404/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
code | string | — | optional |
heading | string | — | optional |
description | string | — | optional |
image | string | /illustrations/error-404.jpg | optional |
image-alt | string | — | optional |
primary-label | string | — | optional |
secondary-label | string | — | optional |
primary-href | string | — | optional |
secondary-href | string | — | optional |
show-primary | boolean | true | optional |
show-secondary | boolean | true | optional |
primary-disabled | boolean | false | optional |
secondary-disabled | boolean | false | optional |
layout | 'page' | 'contained' | page | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
HTMLElementTagNameMapinterface HTMLElementTagNameMap {
'uip-error-404': UipError404
}
}Files installed (1)
src/uip/blocks/error-404/error-404.ts5.5 kB
import { LitElement, css, html, nothing } from 'lit' import { ArrowLeft, LifeBuoy } from 'lucide' import { cn } from '../../lib/utils' import { tailwind } from '../../lib/styles' import { ThemeController } from '../../lib/theme' import { icon } from '../../lib/icon' // Side-effect import: registers <uip-button> for standalone use (consumers // who install only this block still get a working button). import '../../components/button/button' /** * <uip-error-404> — the registry Error404 block as a web component. * * Class strings are React's Error404 verbatim. `heading` is React's `title` * (`title` is taken by HTMLElement). `onPrimary` / `onSecondary` become * `primary` / `secondary` CustomEvents (bubbles, composed). React's * `image === undefined` HTTP-panel branch is unreachable (its default param * fills `image` first), so it is not ported: omit `image` for the default * art, pass `image=""` to hide it. */ export class UipError404 extends LitElement { static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true } // :host display can't be a utility class (the host has no template of its own). static styles = [tailwind, css`:host { display: block; }`] static properties = { code: {}, heading: {}, description: {}, image: {}, imageAlt: { attribute: 'image-alt' }, primaryLabel: { attribute: 'primary-label' }, secondaryLabel: { attribute: 'secondary-label' }, primaryHref: { attribute: 'primary-href' }, secondaryHref: { attribute: 'secondary-href' }, showPrimary: { type: Boolean, attribute: 'show-primary' }, showSecondary: { type: Boolean, attribute: 'show-secondary' }, primaryDisabled: { type: Boolean, attribute: 'primary-disabled' }, secondaryDisabled: { type: Boolean, attribute: 'secondary-disabled' }, layout: { reflect: true }, } code?: string heading?: string description?: string image = '/illustrations/error-404.jpg' imageAlt = '' primaryLabel?: string secondaryLabel?: string primaryHref?: string secondaryHref?: string showPrimary = true showSecondary = true primaryDisabled = false secondaryDisabled = false layout: 'page' | 'contained' = 'page' constructor() { super() new ThemeController(this) } connectedCallback() { super.connectedCallback() this.setAttribute('data-uipkge', '') this.setAttribute('data-slot', 'error-404') this.setAttribute('data-layout', this.layout) } willUpdate() { this.setAttribute('data-layout', this.layout) } private emit(name: 'primary' | 'secondary') { this.dispatchEvent(new CustomEvent(name, { bubbles: true, composed: true })) } render() { const codeText = this.code ?? '404' const titleText = this.heading ?? 'Page not found' const descriptionText = this.description ?? "The page you're looking for doesn't exist or may have been moved. Check the URL or head back home." const primaryText = this.primaryLabel ?? 'Back to home' const secondaryText = this.secondaryLabel ?? 'Contact support' return html` <section data-slot="error-404" data-layout=${this.layout} class=${cn( 'bg-background relative flex items-center overflow-hidden px-6 py-16', this.layout === 'page' ? 'min-h-svh' : 'min-h-[28rem]', )} > <div class="mx-auto grid w-full max-w-5xl items-center gap-10 lg:grid-cols-2 lg:gap-16"> <div> ${codeText ? html`<p class="text-muted-foreground text-sm font-medium">HTTP ${codeText}</p> <p class="mt-3 text-6xl font-semibold tracking-tighter sm:text-7xl">${codeText}</p>` : nothing} <h1 class="mt-3 text-2xl font-semibold tracking-tight sm:text-3xl">${titleText}</h1> ${descriptionText ? html`<p class="text-muted-foreground mt-4 max-w-md text-base">${descriptionText}</p>` : nothing} ${this.showPrimary || this.showSecondary ? html`<div class="mt-8 flex flex-wrap items-center gap-3"> ${this.showPrimary ? html`<uip-button size="lg" ?disabled=${this.primaryDisabled} href=${this.primaryHref ?? nothing} @click=${() => this.emit('primary')} > ${icon(ArrowLeft, 'arrow-left')} ${primaryText} </uip-button>` : nothing} ${this.showSecondary ? html`<uip-button size="lg" variant="outline" ?disabled=${this.secondaryDisabled} href=${this.secondaryHref ?? nothing} @click=${() => this.emit('secondary')} > ${secondaryText} ${icon(LifeBuoy, 'life-buoy')} </uip-button>` : nothing} </div>` : nothing} </div> ${this.image ? html`<div class="border-border bg-muted overflow-hidden rounded-xl border"> <img src=${this.image} alt=${this.imageAlt} class="aspect-[4/3] w-full object-cover" /> </div>` : nothing} </div> </section> ` } } customElements.get('uip-error-404') || customElements.define('uip-error-404', UipError404) declare global { interface HTMLElementTagNameMap { 'uip-error-404': UipError404 } }
Raw manifest:https://uipkge.dev/r/lit/error-404.json