Menu

Change language

GitHub repo

Error Page

blocklayout

Status-screen set with prop-driven 404 and 500 pages plus a four-variant gallery (404, 500, 403, and maintenance) with single-screen, compact-size, and callback controls.

Installation

$npx uipkge-ng@latest add error-page
Manifest:https://uipkge.dev/r/angular/error-page.jsonInstalls to:src/app/components/blocks/error-page/

Variants

Loading interactive previews…

npm dependencies

Includes

Files installed (4)

  • src/app/components/blocks/error-page/error-404.component.ts5.6 kB
    // Full-page 404 shipped inside the error-page set. Same copy and HTTP panel as the
    // standalone error-404 block, with an error-page-scoped selector. 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-page-404, [ui-error-page-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 UiErrorPage404Component {
      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-page/error-500.component.ts6.5 kB
  • src/app/components/blocks/error-page/error-pages.component.ts17.4 kB
  • src/app/components/blocks/error-page/index.ts0.2 kB

Raw manifest:https://uipkge.dev/r/angular/error-page.json