404 Not Found
blocklayoutFull-page 404 with an HTTP response panel, display 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 uipkge-ng@latest add error-404$npx uipkge-ng@latest add error-404$yarn dlx uipkge-ng@latest add error-404$bunx uipkge-ng@latest add error-404Manifest:
https://uipkge.dev/r/angular/error-404.jsonInstalls to:src/app/components/blocks/error-404/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Includes
Files installed (2)
src/app/components/blocks/error-404/error-404.component.ts5.6 kB
// Full-page 404 with an HTTP response panel, display code, headline, and Back to home + // Contact support actions. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core' import { ArrowLeft, LifeBuoy, LucideAngularModule } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiButtonComponent } from '@/ui/button/button.component' @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-error-404, [ui-error-404]', standalone: true, // React renders the root <section> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [LucideAngularModule, UiButtonComponent], template: ` <section data-slot="error-404" [attr.data-layout]="layout" [class]="rootClass"> <div class="mx-auto grid w-full max-w-5xl items-center gap-10 lg:grid-cols-2 lg:gap-16"> <div> @if (codeText) { <p class="text-muted-foreground text-sm font-medium">HTTP {{ codeText }}</p> } @if (codeText) { <p class="mt-3 text-6xl font-semibold tracking-tighter sm:text-7xl">{{ codeText }}</p> } <h1 class="mt-3 text-2xl font-semibold tracking-tight sm:text-3xl">{{ titleText }}</h1> @if (descriptionText) { <p class="text-muted-foreground mt-4 max-w-md text-base">{{ descriptionText }}</p> } @if (showPrimary || showSecondary) { <div class="mt-8 flex flex-wrap items-center gap-3"> @if (showPrimary) { @if (primaryHref) { <a ui-button size="lg" [href]="primaryHref" (click)="primary.emit()"> <lucide-icon [img]="ArrowLeft" /> {{ primaryText }} </a> } @else { <button ui-button size="lg" [disabled]="primaryDisabled" (click)="primary.emit()"> <lucide-icon [img]="ArrowLeft" /> {{ primaryText }} </button> } } @if (showSecondary) { @if (secondaryHref) { <a ui-button size="lg" variant="outline" [href]="secondaryHref" (click)="secondary.emit()"> {{ secondaryText }} <lucide-icon [img]="LifeBuoy" /> </a> } @else { <button ui-button size="lg" variant="outline" [disabled]="secondaryDisabled" (click)="secondary.emit()" > {{ secondaryText }} <lucide-icon [img]="LifeBuoy" /> </button> } } </div> } </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> {{ codeText || '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> } </div> </section> `, }) export class UiError404Component { protected readonly ArrowLeft = ArrowLeft protected readonly LifeBuoy = LifeBuoy @Input() code?: string @Input() title?: string @Input() description?: string /** Replaces the HTTP response panel. Pass `''` to hide art entirely. */ @Input() image: string | undefined = '/illustrations/error-404.jpg' @Input() imageAlt = '' @Input() primaryLabel?: string @Input() secondaryLabel?: string @Input() primaryHref?: string @Input() secondaryHref?: string @Input() showPrimary = true @Input() showSecondary = true @Input() primaryDisabled = false @Input() secondaryDisabled = false @Output() primary = new EventEmitter<void>() @Output() secondary = new EventEmitter<void>() /** `'page'` fills the viewport; `'contained'` fits a preview or nested panel. */ @Input() layout: 'page' | 'contained' = 'page' @Input('class') className?: string get codeText(): string { return this.code === undefined ? '404' : this.code } get titleText(): string { return this.title === undefined ? 'Page not found' : this.title } get descriptionText(): string { return this.description === undefined ? "The page you're looking for doesn't exist or may have been moved. Check the URL or head back home." : this.description } get primaryText(): string { return this.primaryLabel === undefined ? 'Back to home' : this.primaryLabel } get secondaryText(): string { return this.secondaryLabel === undefined ? 'Contact support' : this.secondaryLabel } get rootClass(): string { return cn( 'bg-background relative flex items-center overflow-hidden px-6 py-16', this.layout === 'page' ? 'min-h-svh' : 'min-h-[28rem]', this.className, ) } }src/app/components/blocks/error-404/index.ts0.1 kB
export { UiError404Component } from './error-404.component'
Raw manifest:https://uipkge.dev/r/angular/error-404.json