Layout

A set of layout components for creating common page structures with header, footer, sidebar, and content areas.

PreviousNext
Header
Content
Footer
Header
Content
Footer
Header
Content
Footer
Header
Content
Footer
import { Component } from '@angular/core';
 
import { ContentComponent } from '../content.component';
import { FooterComponent } from '../footer.component';
import { HeaderComponent } from '../header.component';
import { LayoutComponent } from '../layout.component';
import { SidebarComponent } from '../sidebar.component';
 
@Component({
  selector: 'z-demo-layout-basic',
  imports: [LayoutComponent, HeaderComponent, ContentComponent, FooterComponent, SidebarComponent],
  standalone: true,
  template: `
    <div class="flex flex-col gap-6 text-center">
      <z-layout class="overflow-hidden rounded-lg">
        <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
        <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
        <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
      </z-layout>
 
      <z-layout class="overflow-hidden rounded-lg">
        <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
        <z-layout>
          <z-sidebar class="border-0 bg-[#1677ff] text-white" [zWidth]="120">Sidebar</z-sidebar>
          <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
        </z-layout>
        <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
      </z-layout>
 
      <z-layout class="overflow-hidden rounded-lg">
        <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
        <z-layout>
          <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
          <z-sidebar class="border-0 bg-[#1677ff] text-white" [zWidth]="120">Sidebar</z-sidebar>
        </z-layout>
        <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
      </z-layout>
 
      <z-layout class="overflow-hidden rounded-lg">
        <z-sidebar class="border-0 bg-[#1677ff] text-white" [zWidth]="120">Sidebar</z-sidebar>
        <z-layout>
          <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
          <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
          <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
        </z-layout>
      </z-layout>
    </div>
  `,
})
export class LayoutDemoBasicComponent {}
 

Installation

1

Run the CLI

Use the CLI to add the component to your project.

npx @ngzard/ui@latest add layout
1

Add the component files

Create the component directory structure and add the following files to your project.

layout.component.ts
layout.component.ts
import { ChangeDetectionStrategy, Component, computed, contentChildren, input, ViewEncapsulation } from '@angular/core';
 
import type { ClassValue } from 'clsx';
 
import { layoutVariants, type LayoutVariants } from './layout.variants';
import { SidebarComponent } from './sidebar.component';
import { mergeClasses } from '../../shared/utils/utils';
 
@Component({
  selector: 'z-layout',
  standalone: true,
  template: `<ng-content />`,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  host: {
    '[class]': 'classes()',
  },
  exportAs: 'zLayout',
})
export class LayoutComponent {
  readonly class = input<ClassValue>('');
  readonly zDirection = input<LayoutVariants['zDirection']>('auto');
 
  // Query for direct sidebar children to auto-detect layout direction
  private readonly sidebars = contentChildren(SidebarComponent, { descendants: false });
 
  private readonly detectedDirection = computed(() => {
    if (this.zDirection() !== 'auto') {
      return this.zDirection();
    }
 
    // Auto-detection: Check if there are any sidebar children
    const hasSidebar = this.sidebars().length > 0;
    return hasSidebar ? 'horizontal' : 'vertical';
  });
 
  protected readonly classes = computed(() =>
    mergeClasses(
      layoutVariants({
        zDirection: this.detectedDirection() as LayoutVariants['zDirection'],
      }),
      this.class(),
    ),
  );
}
 
layout.variants.ts
layout.variants.ts
import { cva, type VariantProps } from 'class-variance-authority';
 
// Layout Variants
export const layoutVariants = cva('flex w-full min-h-0', {
  variants: {
    zDirection: {
      horizontal: 'flex-row',
      vertical: 'flex-col',
      auto: 'flex-col',
    },
  },
  defaultVariants: {
    zDirection: 'auto',
  },
});
export type LayoutVariants = VariantProps<typeof layoutVariants>;
 
// Header Variants
export const headerVariants = cva('flex items-center px-4 bg-background border-b border-border shrink-0', {
  variants: {},
});
export type HeaderVariants = VariantProps<typeof headerVariants>;
 
// Footer Variants
export const footerVariants = cva('flex items-center px-6 bg-background border-t border-border shrink-0', {
  variants: {},
});
export type FooterVariants = VariantProps<typeof footerVariants>;
 
// Content Variants
export const contentVariants = cva('flex-1 flex flex-col overflow-auto bg-background p-6 min-h-dvh');
export type ContentVariants = VariantProps<typeof contentVariants>;
 
// Sidebar Variants
export const sidebarVariants = cva(
  'relative flex flex-col h-full transition-all duration-300 ease-in-out border-r shrink-0 p-6 bg-sidebar text-sidebar-foreground border-sidebar-border',
);
 
export const sidebarTriggerVariants = cva(
  'absolute bottom-4 z-10 flex items-center justify-center cursor-pointer rounded-sm border border-sidebar-border bg-sidebar hover:bg-sidebar-accent transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring focus-visible:ring-offset-2 w-6 h-6 -right-3',
);
 
// Sidebar Group Variants
export const sidebarGroupVariants = cva('flex flex-col gap-1');
 
export const sidebarGroupLabelVariants = cva(
  'flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 focus-visible:ring-sidebar-ring [&>svg]:size-4 [&>svg]:shrink-0',
);
 
content.component.ts
content.component.ts
import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';
 
import type { ClassValue } from 'clsx';
 
import { contentVariants } from './layout.variants';
import { mergeClasses } from '../../shared/utils/utils';
 
@Component({
  selector: 'z-content',
  standalone: true,
  template: `
    <main>
      <ng-content />
    </main>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  host: {
    '[class]': 'classes()',
  },
  exportAs: 'zContent',
})
export class ContentComponent {
  readonly class = input<ClassValue>('');
 
  protected readonly classes = computed(() => mergeClasses(contentVariants(), this.class()));
}
 
footer.component.ts
footer.component.ts
import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';
 
import type { ClassValue } from 'clsx';
 
import { footerVariants } from './layout.variants';
import { mergeClasses } from '../../shared/utils/utils';
 
@Component({
  selector: 'z-footer',
  standalone: true,
  template: `
    <footer [class]="classes()" [style.height.px]="zHeight()">
      <ng-content />
    </footer>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  exportAs: 'zFooter',
})
export class FooterComponent {
  readonly class = input<ClassValue>('');
  readonly zHeight = input<number>(64);
 
  protected readonly classes = computed(() => mergeClasses(footerVariants(), this.class()));
}
 
header.component.ts
header.component.ts
import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';
 
import type { ClassValue } from 'clsx';
 
import { headerVariants } from './layout.variants';
import { mergeClasses } from '../../shared/utils/utils';
 
@Component({
  selector: 'z-header',
  standalone: true,
  template: `
    <header [class]="classes()" [style.height.px]="zHeight()">
      <ng-content />
    </header>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  exportAs: 'zHeader',
})
export class HeaderComponent {
  readonly class = input<ClassValue>('');
  readonly zHeight = input<number>(64);
 
  protected readonly classes = computed(() => mergeClasses(headerVariants(), this.class()));
}
 
layout.module.ts
layout.module.ts
import { NgModule } from '@angular/core';
 
import { ContentComponent } from './content.component';
import { FooterComponent } from './footer.component';
import { HeaderComponent } from './header.component';
import { LayoutComponent } from './layout.component';
import { SidebarGroupLabelComponent, SidebarGroupComponent, SidebarComponent } from './sidebar.component';
 
const LAYOUT_COMPONENTS = [
  LayoutComponent,
  HeaderComponent,
  FooterComponent,
  ContentComponent,
  SidebarComponent,
  SidebarGroupComponent,
  SidebarGroupLabelComponent,
];
 
@NgModule({
  imports: [LAYOUT_COMPONENTS],
  exports: [LAYOUT_COMPONENTS],
})
export class LayoutModule {}
 
sidebar.component.ts
sidebar.component.ts
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  effect,
  input,
  output,
  signal,
  type TemplateRef,
  ViewEncapsulation,
} from '@angular/core';
 
import type { ClassValue } from 'clsx';
 
import {
  sidebarGroupLabelVariants,
  sidebarGroupVariants,
  sidebarTriggerVariants,
  sidebarVariants,
} from './layout.variants';
import { mergeClasses, transform } from '../../shared/utils/utils';
import { ZardStringTemplateOutletDirective } from '../core/directives/string-template-outlet/string-template-outlet.directive';
import { ZardIconComponent } from '../icon/icon.component';
import type { ZardIcon } from '../icon/icons';
 
@Component({
  selector: 'z-sidebar',
  imports: [ZardStringTemplateOutletDirective, ZardIconComponent],
  standalone: true,
  template: `
    <aside [class]="classes()" [style.width.px]="currentWidth()" [attr.data-collapsed]="zCollapsed()">
      <div class="flex-1 overflow-auto">
        <ng-content />
      </div>
 
      @if (zCollapsible() && !zTrigger()) {
        <div
          [class]="triggerClasses()"
          (click)="toggleCollapsed()"
          (keydown.enter)="toggleCollapsed(); $event.preventDefault()"
          (keydown.space)="toggleCollapsed(); $event.preventDefault()"
          tabindex="0"
          role="button"
          [attr.aria-label]="zCollapsed() ? 'Expand sidebar' : 'Collapse sidebar'"
          [attr.aria-expanded]="!zCollapsed()"
        >
          <z-icon [zType]="chevronIcon()" />
        </div>
      }
 
      @if (zCollapsible() && zTrigger()) {
        <ng-container *zStringTemplateOutlet="zTrigger()" />
      }
    </aside>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  exportAs: 'zSidebar',
})
export class SidebarComponent {
  readonly zWidth = input<string | number>(200);
  readonly zCollapsedWidth = input<number>(64);
  readonly zCollapsible = input(false, { transform });
  readonly zCollapsed = input(false, { transform });
  readonly zReverseArrow = input(false, { transform });
  readonly zTrigger = input<TemplateRef<void> | null>(null);
  readonly class = input<ClassValue>('');
 
  readonly zCollapsedChange = output<boolean>();
 
  private readonly internalCollapsed = signal(false);
 
  constructor() {
    effect(() => {
      this.internalCollapsed.set(this.zCollapsed());
    });
  }
 
  protected readonly currentWidth = computed(() => {
    const collapsed = this.zCollapsed();
    if (collapsed) {
      return this.zCollapsedWidth();
    }
 
    const width = this.zWidth();
    return typeof width === 'number' ? width : parseInt(width, 10);
  });
 
  protected readonly chevronIcon = computed((): ZardIcon => {
    const collapsed = this.zCollapsed();
    const reverse = this.zReverseArrow();
 
    if (reverse) {
      return collapsed ? 'chevron-left' : 'chevron-right';
    }
    return collapsed ? 'chevron-right' : 'chevron-left';
  });
 
  protected readonly classes = computed(() => mergeClasses(sidebarVariants(), this.class()));
 
  protected readonly triggerClasses = computed(() => mergeClasses(sidebarTriggerVariants()));
 
  toggleCollapsed(): void {
    const newState = !this.zCollapsed();
    this.internalCollapsed.set(newState);
    this.zCollapsedChange.emit(newState);
  }
}
 
@Component({
  selector: 'z-sidebar-group',
  standalone: true,
  template: `
    <div [class]="classes()">
      <ng-content />
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  exportAs: 'zSidebarGroup',
})
export class SidebarGroupComponent {
  readonly class = input<ClassValue>('');
 
  protected readonly classes = computed(() => mergeClasses(sidebarGroupVariants(), this.class()));
}
 
@Component({
  selector: 'z-sidebar-group-label',
  standalone: true,
  template: `
    <div [class]="classes()">
      <ng-content />
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  exportAs: 'zSidebarGroupLabel',
})
export class SidebarGroupLabelComponent {
  readonly class = input<ClassValue>('');
 
  protected readonly classes = computed(() => mergeClasses(sidebarGroupLabelVariants(), this.class()));
}
 

Examples

basic

Header
Content
Footer
Header
Content
Footer
Header
Content
Footer
Header
Content
Footer
import { Component } from '@angular/core';
 
import { ContentComponent } from '../content.component';
import { FooterComponent } from '../footer.component';
import { HeaderComponent } from '../header.component';
import { LayoutComponent } from '../layout.component';
import { SidebarComponent } from '../sidebar.component';
 
@Component({
  selector: 'z-demo-layout-basic',
  imports: [LayoutComponent, HeaderComponent, ContentComponent, FooterComponent, SidebarComponent],
  standalone: true,
  template: `
    <div class="flex flex-col gap-6 text-center">
      <z-layout class="overflow-hidden rounded-lg">
        <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
        <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
        <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
      </z-layout>
 
      <z-layout class="overflow-hidden rounded-lg">
        <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
        <z-layout>
          <z-sidebar class="border-0 bg-[#1677ff] text-white" [zWidth]="120">Sidebar</z-sidebar>
          <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
        </z-layout>
        <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
      </z-layout>
 
      <z-layout class="overflow-hidden rounded-lg">
        <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
        <z-layout>
          <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
          <z-sidebar class="border-0 bg-[#1677ff] text-white" [zWidth]="120">Sidebar</z-sidebar>
        </z-layout>
        <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
      </z-layout>
 
      <z-layout class="overflow-hidden rounded-lg">
        <z-sidebar class="border-0 bg-[#1677ff] text-white" [zWidth]="120">Sidebar</z-sidebar>
        <z-layout>
          <z-header class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Header</z-header>
          <z-content class="min-h-[200px] bg-[#0958d9] text-white">Content</z-content>
          <z-footer class="h-16 justify-center border-0 bg-[#4096ff] px-12 text-white">Footer</z-footer>
        </z-layout>
      </z-layout>
    </div>
  `,
})
export class LayoutDemoBasicComponent {}
 

sidebar

import { Component, signal } from '@angular/core';
 
import { ZardAvatarComponent } from '../../avatar/avatar.component';
import { ZardBreadcrumbModule } from '../../breadcrumb/breadcrumb.module';
import { ZardButtonComponent } from '../../button/button.component';
import { ZardDividerComponent } from '../../divider/divider.component';
import { ZardIconComponent } from '../../icon/icon.component';
import type { ZardIcon } from '../../icon/icons';
import { ZardMenuModule } from '../../menu/menu.module';
import { ZardSkeletonComponent } from '../../skeleton/skeleton.component';
import { ZardTooltipModule } from '../../tooltip/tooltip';
import { LayoutModule } from '../layout.module';
 
interface MenuItem {
  icon: ZardIcon;
  label: string;
  submenu?: { label: string }[];
}
 
@Component({
  selector: 'z-demo-layout-collapsible',
  imports: [
    LayoutModule,
    ZardButtonComponent,
    ZardBreadcrumbModule,
    ZardMenuModule,
    ZardSkeletonComponent,
    ZardTooltipModule,
    ZardDividerComponent,
    ZardAvatarComponent,
    ZardIconComponent,
  ],
  standalone: true,
  template: `
    <!-- border and rounded-md are just for the demo purpose -->
    <z-layout class="overflow-hidden rounded-md border">
      <z-sidebar
        [zWidth]="250"
        [zCollapsible]="true"
        [zCollapsed]="sidebarCollapsed()"
        [zCollapsedWidth]="70"
        (zCollapsedChange)="onCollapsedChange($event)"
        class="p-0!"
      >
        <nav [class]="'flex h-full flex-col overflow-hidden ' + (sidebarCollapsed() ? 'gap-1 p-1 pt-4' : 'gap-4 p-4')">
          <z-sidebar-group>
            @if (!sidebarCollapsed()) {
              <z-sidebar-group-label>Main</z-sidebar-group-label>
            }
            @for (item of mainMenuItems; track item.label) {
              <button
                type="button"
                z-button
                zType="ghost"
                [class]="sidebarCollapsed() ? 'justify-center' : 'justify-start'"
                [zTooltip]="sidebarCollapsed() ? item.label : ''"
                zPosition="right"
              >
                <z-icon [zType]="item.icon" [class]="sidebarCollapsed() ? '' : 'mr-2'" />
                @if (!sidebarCollapsed()) {
                  <span>{{ item.label }}</span>
                }
              </button>
            }
          </z-sidebar-group>
 
          <z-sidebar-group>
            @if (!sidebarCollapsed()) {
              <z-sidebar-group-label>Workspace</z-sidebar-group-label>
            }
            @for (item of workspaceMenuItems; track item.label) {
              @if (item.submenu) {
                <button
                  type="button"
                  z-button
                  zType="ghost"
                  z-menu
                  [zMenuTriggerFor]="submenu"
                  zPlacement="rightTop"
                  [class]="sidebarCollapsed() ? 'justify-center' : 'justify-start'"
                  [zTooltip]="sidebarCollapsed() ? item.label : null"
                  zPosition="right"
                >
                  <z-icon [zType]="item.icon" [class]="sidebarCollapsed() ? '' : 'mr-2'" />
                  @if (!sidebarCollapsed()) {
                    <span class="flex-1 text-left">{{ item.label }}</span>
                    <z-icon zType="chevron-right" />
                  }
                </button>
 
                <ng-template #submenu>
                  <div z-menu-content class="w-48">
                    @for (subitem of item.submenu; track subitem.label) {
                      <button type="button" z-menu-item>{{ subitem.label }}</button>
                    }
                  </div>
                </ng-template>
              } @else {
                <button
                  type="button"
                  z-button
                  zType="ghost"
                  [class]="sidebarCollapsed() ? 'justify-center' : 'justify-start'"
                  [zTooltip]="sidebarCollapsed() ? item.label : ''"
                  zPosition="right"
                >
                  <z-icon [zType]="item.icon" [class]="sidebarCollapsed() ? '' : 'mr-2'" />
                  @if (!sidebarCollapsed()) {
                    <span>{{ item.label }}</span>
                  }
                </button>
              }
            }
          </z-sidebar-group>
 
          <div class="mt-auto">
            <div
              z-menu
              [zMenuTriggerFor]="userMenu"
              zPlacement="rightBottom"
              [class]="
                'hover:bg-accent flex cursor-pointer items-center justify-center gap-2 rounded-md ' +
                (sidebarCollapsed() ? 'm-2 p-0' : 'p-2')
              "
            >
              <z-avatar zSrc="https://zardui.com/images/avatar/imgs/avatar_image.jpg" zAlt="Zard UI" />
 
              @if (!sidebarCollapsed()) {
                <div>
                  <span class="font-medium">zardui</span>
                  <div class="text-xs">test&#64;zardui.com</div>
                </div>
 
                <z-icon zType="chevrons-up-down" class="ml-auto" />
              }
            </div>
 
            <ng-template #userMenu>
              <div z-menu-content class="w-48">
                <button type="button" z-menu-item>
                  <z-icon zType="user" class="mr-2" />
                  Profile
                </button>
                <button type="button" z-menu-item>
                  <z-icon zType="settings" class="mr-2" />
                  Settings
                </button>
                <z-divider zSpacing="sm" />
                <button type="button" z-menu-item>
                  <z-icon zType="log-out" class="mr-2" />
                  Logout
                </button>
              </div>
            </ng-template>
          </div>
        </nav>
      </z-sidebar>
 
      <!-- min-h-[200px] is just for the demo purpose to have a minimum height -->
      <z-content class="min-h-[200px]">
        <div class="flex items-center">
          <button type="button" z-button zType="ghost" zSize="sm" class="-ml-2" (click)="toggleSidebar()">
            <z-icon zType="panel-left" />
          </button>
 
          <z-divider zOrientation="vertical" class="ml-2 h-4" />
 
          <z-breadcrumb zWrap="wrap" zAlign="start">
            <z-breadcrumb-item [routerLink]="['/docs/components/layout']">Home</z-breadcrumb-item>
            <z-breadcrumb-item>
              <span aria-current="page">Components</span>
            </z-breadcrumb-item>
          </z-breadcrumb>
        </div>
 
        <div class="space-y-4 py-4">
          <z-skeleton class="h-80 w-full" />
          <z-skeleton class="h-16 w-full" />
        </div>
      </z-content>
    </z-layout>
  `,
})
export class LayoutDemoSidebarComponent {
  readonly sidebarCollapsed = signal(false);
 
  mainMenuItems: MenuItem[] = [
    { icon: 'house', label: 'Home' },
    { icon: 'inbox', label: 'Inbox' },
  ];
 
  workspaceMenuItems: MenuItem[] = [
    {
      icon: 'folder',
      label: 'Projects',
      submenu: [{ label: 'Design System' }, { label: 'Mobile App' }, { label: 'Website' }],
    },
    { icon: 'calendar', label: 'Calendar' },
    { icon: 'search', label: 'Search' },
  ];
 
  toggleSidebar() {
    this.sidebarCollapsed.update(collapsed => !collapsed);
  }
 
  onCollapsedChange(collapsed: boolean) {
    this.sidebarCollapsed.set(collapsed);
  }
}
 

full layout

LogoZardUI
© 2025 ZardUI
import { Component } from '@angular/core';
 
import { ZardButtonComponent } from '../../button/button.component';
import { ZardIconComponent } from '../../icon/icon.component';
import { ZardSkeletonComponent } from '../../skeleton/skeleton.component';
import { ContentComponent } from '../content.component';
import { FooterComponent } from '../footer.component';
import { HeaderComponent } from '../header.component';
import { LayoutComponent } from '../layout.component';
import { SidebarComponent, SidebarGroupComponent, SidebarGroupLabelComponent } from '../sidebar.component';
 
@Component({
  selector: 'z-demo-layout-full',
  imports: [
    LayoutComponent,
    HeaderComponent,
    ContentComponent,
    FooterComponent,
    SidebarComponent,
    SidebarGroupComponent,
    SidebarGroupLabelComponent,
    ZardButtonComponent,
    ZardSkeletonComponent,
    ZardIconComponent,
  ],
  standalone: true,
  template: `
    <z-layout class="min-h-[600px] overflow-hidden rounded-md border">
      <z-header>
        <div class="flex w-full items-center justify-between">
          <div class="flex items-center text-lg font-semibold">
            <img src="images/zard.svg" alt="Logo" width="24" height="24" />
            <span class="ml-2">ZardUI</span>
          </div>
          <div class="flex items-center gap-2">
            <button z-button zType="ghost" zSize="sm">
              <z-icon zType="search" />
            </button>
            <button z-button zType="ghost" zSize="sm">
              <z-icon zType="bell" />
            </button>
          </div>
        </div>
      </z-header>
 
      <z-layout>
        <z-sidebar [zWidth]="200" class="!p-0">
          <nav class="flex h-full flex-col gap-2 p-4">
            <z-sidebar-group>
              <z-sidebar-group-label>Menu</z-sidebar-group-label>
              <button z-button zType="secondary" class="justify-start">
                <z-icon zType="house" class="mr-2" />
                Dashboard
              </button>
              <button z-button zType="ghost" class="justify-start">
                <z-icon zType="layers" class="mr-2" />
                Projects
              </button>
              <button z-button zType="ghost" class="justify-start">
                <z-icon zType="users" class="mr-2" />
                Team
              </button>
            </z-sidebar-group>
          </nav>
        </z-sidebar>
 
        <z-layout>
          <z-content class="min-h-[200px]">
            <div class="space-y-4">
              <z-skeleton class="h-32 w-full" />
              <z-skeleton class="h-48 w-full" />
              <z-skeleton class="h-24 w-full" />
            </div>
          </z-content>
 
          <z-footer>
            <div class="text-muted-foreground flex w-full items-center justify-center text-sm">
              © {{ year }} ZardUI
            </div>
          </z-footer>
        </z-layout>
      </z-layout>
    </z-layout>
  `,
})
export class LayoutDemoFullComponent {
  year = new Date().getFullYear();
}
 

API Reference

z-layout

Property Description Type Default
[class] Additional CSS classes ClassValue ''
[zDirection] Flex direction (auto-detects based on children) 'horizontal' | 'vertical' | 'auto' 'auto'

z-header

Property Description Type Default
[class] Additional CSS classes ClassValue ''
[zHeight] Header height in pixels number 64

Property Description Type Default
[class] Additional CSS classes ClassValue ''
[zHeight] Footer height in pixels number 64

z-content

Property Description Type Default
[class] Additional CSS classes ClassValue ''

z-sidebar

Inputs

Property Description Type Default
[class] Additional CSS classes ClassValue ''
[zWidth] Sidebar width when expanded (px or string) string | number 200
[zCollapsedWidth] Sidebar width when collapsed (px) number 64
[zCollapsible] Enable collapse functionality boolean false
[zCollapsed] Collapsed state (supports two-way binding) boolean false
[zReverseArrow] Reverse trigger arrow direction boolean false
[zTrigger] Custom trigger template TemplateRef<void> | null null
(zCollapsedChange) Emitted when collapsed state changes EventEmitter<boolean>

z-sidebar-group

Property Description Type Default
[class] Additional CSS classes ClassValue ''

z-sidebar-group-label

Property Description Type Default
[class] Additional CSS classes ClassValue ''