tuiSlides to indicate backward direction, positive for forward direction and 0 for static crossfade. Important: each child must be exactly one DOM element.
<div tuiGroup>
<button
appearance="secondary"
iconStart="@tui.chevron-left"
size="m"
tuiIconButton
type="button"
[disabled]="!index"
(click)="index = index - 1"
>
Previous
</button>
<button
appearance="secondary"
iconStart="@tui.chevron-right"
size="m"
tuiIconButton
type="button"
[disabled]="index === items.length - 1"
(click)="index = index + 1"
>
Next
</button>
</div>
<tui-elastic-container>
<section tuiSlides>
@for (item of items; track item) {
@if ($index === index) {
<div tuiTitle>
{{ item }}
<div tuiSubtitle>{{ item.repeat(10) }}</div>
</div>
}
}
</section>
</tui-elastic-container>
[tuiGroup] {
inline-size: fit-content;
margin: 0 auto 1rem;
}
[tuiSubtitle] {
color: var(--tui-text-secondary);
}
[tuiTitle] {
--tui-duration: 0.6s;
animation-delay: 0.3s;
&.tui-leave {
animation-delay: 0s;
}
}
<tui-stepper
[activeItemIndex]="index"
(activeItemIndexChange)="onStep($event)"
>
<button tuiStep>Personal details</button>
<button tuiStep>Shipping address</button>
<button tuiStep>Payment info</button>
</tui-stepper>
<tui-elastic-container>
<section [tuiSlides]="direction">
@for (form of forms; track form; let i = $index) {
@if (i === index) {
<form
appearance="floating"
tuiCardLarge
tuiForm
[formGroup]="form"
[id]="`form_${i}`"
(ngSubmit)="onSubmit()"
>
<header tuiHeader>
<h2 tuiTitle>
Registration form
<span tuiSubtitle>Tell us about yourself</span>
</h2>
</header>
@for (control of form.controls | keyvalue; track control; let j = $index) {
<tui-textfield>
<label tuiLabel>{{ control.key }}</label>
<input
tuiInput
[formControlName]="control.key"
[tuiAutoFocus]="!!index && !j"
/>
</tui-textfield>
}
</form>
}
}
</section>
</tui-elastic-container>
<footer>
<button
appearance="secondary"
tuiButton
type="button"
[disabled]="!index"
(click)="index = index - 1"
>
Back
</button>
<button
tuiButton
type="submit"
[attr.form]="`form_${index}`"
>
Next
</button>
</footer>
tui-elastic-container {
padding: 2rem;
margin: 0 -2rem;
}
footer {
display: flex;
justify-content: space-between;
}
<tui-tabs [activeItemIndex]="-1">
<a
routerLink="1"
routerLinkActive
tuiTab
>
Home
</a>
<a
routerLink="2"
routerLinkActive
tuiTab
>
Notifications
</a>
<a
routerLink="3"
routerLinkActive
tuiTab
>
Settings
</a>
</tui-tabs>
<p [tuiSlides]="direction()">
<router-outlet />
</p>
<button
tuiButton
type="button"
(click)="onClick()"
>
Show dialog
</button>
<ng-template let-observer>
<tui-app-bar tuiAppBarSize>
@if (step > 1) {
<button
tuiButton
tuiSlot="start"
type="button"
(click)="onStep(-1)"
>
Back
</button>
}
<progress
size="s"
tuiProgressBar
[max]="3"
[style.width.rem]="10"
[value]="step"
></progress>
<button
tuiButton
tuiSlot="end"
type="button"
(click)="observer.complete()"
>
Close
</button>
</tui-app-bar>
<section [tuiSlides]="direction">
@switch (step) {
@case (1) {
<div>
<header>Welcome to the slides demo</header>
<p>
These wrapping components will be animated upon navigating this modal dialog. This works well on
both desktop and mobile. In your own layouts watch out for unwanted scrollbars.
</p>
</div>
}
@case (2) {
<div>
<header>Header is optional</header>
<section [style.margin]="'0 -1rem'">
@for (_ of '-'.repeat(5); track $index) {
<div tuiCell>
<div
appearance="primary"
tuiAvatar="@tui.star"
></div>
<div tuiTitle>
Title
<div tuiSubtitle>Description</div>
</div>
</div>
}
</section>
</div>
}
@case (3) {
<div
appearance="floating"
tuiCardLarge
>
<header tuiHeader>
<h1 tuiTitle>
Title
<span tuiSubtitle>Subtitle</span>
</h1>
<aside tuiAccessories>
<div
appearance="primary"
tuiAvatar="@tui.star"
></div>
</aside>
</header>
<footer>
<button
appearance="secondary"
size="m"
tuiButton
type="button"
>
Label
</button>
</footer>
</div>
}
}
</section>
<footer
tuiFloatingContainer
[style.margin-block-start]="'auto'"
>
<button
tuiButton
type="button"
(click)="step < 3 ? onStep(1) : observer.complete()"
>
{{ step < 3 ? 'Next' : 'OK' }}
</button>
</footer>
</ng-template>