AvesraAvesrabeta

Slider

A slider allows a user to select one or more values within a range.

Import

import { AvSliderImports } from '@avesra/angular';

Usage

30
import { Component } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-basic-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div class="w-full max-w-xs" av-slider [default-value]="30">
  <label av-label>Volume</label>
  <span av-slider-output></span>
  <div av-slider-track>
    <div av-slider-fill></div>
    <div av-slider-thumb></div>
  </div>
</div>`,
})
export class SliderBasicDemo {}

Anatomy

Import the Slider parts and compose them with attribute selectors on <div>, <span>, and <label> hosts. Pair with shared av-label for accessible labeling.

<div av-slider [default-value]="30">
  <label av-label>Volume</label>
  <span av-slider-output></span>
  <div av-slider-track>
    <div av-slider-fill></div>
    <div av-slider-thumb></div>
  </div>
</div>

Range Slider Anatomy

For a dual-thumb range, pass a number array to default-value or [(value)], and add a second av-slider-thumb with [index]="1".

<div av-slider [default-value]="[25, 75]">
  <label av-label>Range</label>
  <span av-slider-output></span>
  <div av-slider-track>
    <div av-slider-fill></div>
    <div av-slider-thumb [index]="0"></div>
    <div av-slider-thumb [index]="1"></div>
  </div>
</div>

Disabled

Set the disabled attribute to prevent interaction and apply disabled styling.

30
import { Component } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-disabled-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div class="w-full max-w-xs" av-slider disabled [default-value]="30">
  <label av-label>Volume</label>
  <span av-slider-output></span>
  <div av-slider-track>
    <div av-slider-fill></div>
    <div av-slider-thumb></div>
  </div>
</div>`,
})
export class SliderDisabledDemo {}

Vertical

Set orientation="vertical" for a vertical track layout.

30
import { Component } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-vertical-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div class="flex h-64 items-center justify-center">
  <div class="h-full" av-slider orientation="vertical" [default-value]="30" aria-label="Volume">
    <label av-label>Volume</label>
    <span av-slider-output></span>
    <div av-slider-track>
      <div av-slider-fill></div>
      <div av-slider-thumb></div>
    </div>
  </div>
</div>`,
})
export class SliderVerticalDemo {}

Range

Provide two av-slider-thumb elements with [index]="0" and [index]="1", and bind a number array for the value.

$100.00 – $500.00
import { Component } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-range-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div
  class="w-full max-w-xs"
  av-slider
  [default-value]="[100, 500]"
  [format-options]="{ style: 'currency', currency: 'USD' }"
  [max]="1000"
  [min]="0"
  [step]="50"
>
  <label av-label>Price Range</label>
  <span av-slider-output></span>
  <div av-slider-track>
    <div av-slider-fill></div>
    <div av-slider-thumb [index]="0"></div>
    <div av-slider-thumb [index]="1"></div>
  </div>
</div>`,
})
export class SliderRangeDemo {}

Controlled

Drive the value from the parent with [(value)] two-way binding.

25

Current value: 25

import { Component, signal } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-controlled-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div class="flex w-full max-w-xs flex-col gap-3">
  <div av-slider [(value)]="volume">
    <label av-label>Volume</label>
    <span av-slider-output></span>
    <div av-slider-track>
      <div av-slider-fill></div>
      <div av-slider-thumb></div>
    </div>
  </div>
  <p class="text-sm text-muted">Current value: {{ volume() }}</p>
</div>`,
})
export class SliderControlledDemo {
  readonly volume = signal(25);
}

Custom Value Formatting

Pass format-options ( Intl.NumberFormatOptions) to format the output label — for example currency.

$60.00
import { Component } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-custom-formatting-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div
  class="w-full max-w-xs"
  av-slider
  [default-value]="60"
  [format-options]="{ style: 'currency', currency: 'USD' }"
>
  <label av-label>Price</label>
  <span av-slider-output></span>
  <div av-slider-track>
    <div av-slider-fill></div>
    <div av-slider-thumb></div>
  </div>
</div>`,
})
export class SliderCustomFormattingDemo {}

Custom Output Display

Project custom content into av-slider-output to replace the default formatted value display.

25% – 75%
import { Component, computed, signal } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-custom-output-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div class="w-full max-w-xs" av-slider [(value)]="range">
  <label av-label>Range</label>
  <span av-slider-output>{{ outputLabel() }}</span>
  <div av-slider-track>
    <div av-slider-fill></div>
    <div av-slider-thumb [index]="0"></div>
    <div av-slider-thumb [index]="1"></div>
  </div>
</div>`,
})
export class SliderCustomOutputDemo {
  readonly range = signal<number[]>([25, 75]);
  readonly outputLabel = computed(() => {
    const [start, end] = this.range();
    return `${start}% – ${end}%`;
  });
}

Reactive form

Integrate with Angular reactive forms using formControlName or [formControl] on div[av-slider].

65

Form value: { "brightness": 65 }

import { Component } from '@angular/core';
import { JsonPipe } from '@angular/common';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-reactive-form-demo',
  imports: [
    JsonPipe,
    ReactiveFormsModule,
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<form class="flex w-full max-w-xs flex-col gap-3" [formGroup]="settingsForm">
  <div av-slider formControlName="brightness">
    <label av-label>Brightness</label>
    <span av-slider-output></span>
    <div av-slider-track>
      <div av-slider-fill></div>
      <div av-slider-thumb></div>
    </div>
  </div>
  <p class="text-sm text-muted">Form value: {{ settingsForm.value | json }}</p>
</form>`,
})
export class SliderReactiveFormDemo {
  readonly settingsForm = new FormGroup({
    brightness: new FormControl(65),
  });
}

Styling

Passing Tailwind CSS classes

Pass utility classes on individual Slider parts — for example av-slider-track, av-slider-fill, and av-slider-thumb.

40
import { Component } from '@angular/core';
import {
  AvLabelComponent,
  AvSliderImports,
} from '@avesra/angular';

@Component({
  selector: 'app-slider-custom-styling-demo',
  imports: [
    AvSliderImports,
    AvLabelComponent,
  ],
  host: { class: 'flex w-full items-center flex-col gap-3' },
  template: `<div class="w-full max-w-xs" av-slider [default-value]="40">
  <label av-label>Volume</label>
  <span av-slider-output class="text-muted text-sm"></span>
  <div av-slider-track class="!bg-surface-secondary">
    <div av-slider-fill class="!bg-accent"></div>
    <div av-slider-thumb></div>
  </div>
</div>`,
})
export class SliderCustomStylingDemo {}

Customizing the component classes

To customize the Slider classes, use the @layer components directive. Learn more.

@layer components {
  .av-slider {
    @apply flex flex-col gap-2;
  }

  .av-slider__output {
    @apply text-muted text-sm;
  }

  .av-slider__track {
    @apply relative h-2 w-full rounded-full bg-surface-secondary;
  }

  .av-slider__fill {
    @apply absolute h-full rounded-full bg-accent;
  }

  .av-slider__thumb {
    @apply size-4 rounded-full border-2 border-background bg-accent;
  }
}

Avesra follows the BEM methodology so component variants and states stay reusable and easy to customize.

CSS Classes

The Slider component uses these CSS classes:

Base Classes

  • .av-slider — Base slider container
  • .av-slider__output — Output element displaying current value(s)
  • .av-slider__track — Track element containing fill and thumbs
  • .av-slider__fill — Fill element showing selected range
  • .av-slider__thumb — Individual thumb element

Orientation Classes

  • .av-slider--horizontal — Horizontal orientation (default)
  • .av-slider--vertical — Vertical orientation

State Classes

  • .av-slider[data-disabled="true"] — Disabled slider state
  • .av-slider[data-orientation="vertical"] — Vertical orientation
  • .av-slider__thumb[data-dragging="true"] — Thumb being dragged
  • .av-slider__thumb[data-focus-visible="true"] — Thumb keyboard focused
  • .av-slider__thumb[data-disabled="true"] — Disabled thumb state
  • .av-slider__track[data-fill-start="true"] — Fill starts at beginning
  • .av-slider__track[data-fill-end="true"] — Fill ends at end

Interactive States

The component supports both CSS pseudo-classes and data attributes:

  • Focus::focus-visible or [data-focus-visible="true"] on thumb
  • Dragging:[data-dragging="true"] on thumb
  • Disabled::disabled, [data-disabled="true"], or [aria-disabled="true"] on slider or thumb

Accessibility

Slider implements the ARIA slider pattern and provides:

  • Full keyboard navigation support (Arrow keys, Home, End)
  • aria-valuenow, aria-valuemin, and aria-valuemax on thumbs
  • Screen reader announcements for value changes
  • Proper focus management on thumb elements
  • Support for disabled states
  • HTML form integration through ControlValueAccessor (ngModel / formControlName)
  • Locale-aware value formatting via format-options

Associate a visible av-label or set aria-label on div[av-slider] when no visible label is present.

API

Props for div[av-slider]. span[av-slider-output], div[av-slider-track], and div[av-slider-fill] project content / render the track and have no inputs. Compose with shared label[av-label] when a visible label is needed.

PropTypeDefaultDescription
valuenumber | number[]—The current value (controlled). Supports two-way binding with `[(value)]`.
default-valuenumber | number[]0The default value (uncontrolled). Use a number array for range sliders.
valueChangeEventEmitter<number | number[]>—Emits when the value changes (from `model()` two-way binding).
minnumber0The slider's minimum value.
maxnumber100The slider's maximum value.
stepnumber1The slider's step value.
format-optionsIntl.NumberFormatOptions—The display format of the value label on `av-slider-output`.
orientation'horizontal' | 'vertical''horizontal'The orientation of the slider.
disabledbooleanfalseWhether the slider is disabled. Also set by reactive forms.

av-slider-thumb

PropTypeDefaultDescription
indexnumber0Index of the thumb within the slider. Use `0` and `1` for range sliders.

Made with ❤ by SyntaxHertz. Open source and available on GitHub.