Package Exports
- @3nvs/polyfront-slider
Readme
๐๏ธ @3nvs/polyfront-slider (v1.1.4)
The official scoped package for the Polyfront Slider Web Component โ built with TypeScript, accessible, framework-agnostic, and optimized for modern apps.
โจ Overview
polyfront-slider is an open-source Web Component slider that works in React, Vue, Angular, Svelte, or plain HTML/JS.
It provides enterprise-grade configurability, theming tokens, accessibility, and form integration โ all in a single, dependency-free package.
๐ Key Features
| Category | Highlights |
|---|---|
| ๐จ UI/UX | OKLCH color system, dark mode, hover/active/focus states, large touch targets, and elevation shadows. |
| ๐งฉ Configurable | Supports {min, max, step} or discrete arrays like [0,1500,1600,โฆ]. Auto-detects step size and disables missing values. |
| ๐งฑ Modes | Single or dual-thumb (range) slider. |
| ๐ง Smart Logic | Auto GCD step detection, blocked intervals, minimum thumb distance. |
| โฟ Accessible | Full WAI-ARIA compliance, keyboard navigation, and form-associated support. |
| ๐ฅ๏ธ Responsive | 100 % width, mobile-friendly, fits any layout. |
| ๐ Themeable | Size presets (sm,md,lg), CSS tokens, and dark/light mode support. |
| ๐งช Reliable | TypeScript + Vitest + Storybook 8.6 + GitHub CI. |
| ๐งฐ Reusable | Works standalone or via npm import in any framework. |
๐งฉ Installation
# Scoped (recommended)
npm install @3nvs/polyfront-slider
# or use alias (unscoped)
npm install polyfront-slider๐งโ๐ป Usage
๐ Quick Start
1๏ธโฃ Register the component
import { definePolyfrontSlider } from '@3nvs/polyfront-slider';
definePolyfrontSlider();2๏ธโฃ Add to your HTML / JSX
<polyfront-slider id="price-slider" style="inline-size:100%;max-inline-size:480px"></polyfront-slider>3๏ธโฃ Configure dynamically
const slider = document.getElementById('price-slider');
slider.setConfig({
mode: 'range',
orientation: 'horizontal',
size: 'md',
values: [0,1500,1600,1700,1800,1900,2000],
showTicks: true,
showLabels: true,
showTooltip: true,
tickEvery: 1,
disableMissingSteps: true,
blockedIntervals: [[1600,1699]],
minThumbDistance: 1,
name: 'price'
});๐ฏ Helper Functions (Recommended)
For easier usage across frameworks, use these helper functions:
Range Slider
import { createRangeSlider } from '@3nvs/polyfront-slider';
const priceSlider = createRangeSlider(0, 2000, 100);
document.body.appendChild(priceSlider);Volume Control
import { createVolumeControl } from '@3nvs/polyfront-slider';
const volumeControl = createVolumeControl(100);
volumeControl.style.height = '200px';
document.body.appendChild(volumeControl);Price Slider with Discrete Values
import { createPriceSlider } from '@3nvs/polyfront-slider';
const priceSlider = createPriceSlider([0, 1500, 1600, 1700, 1800, 1900, 2000]);
document.body.appendChild(priceSlider);Discrete Value Slider (Sizes, Ratings, etc.)
import { createDiscreteSlider } from '@3nvs/polyfront-slider';
// Size selector
const sizeSlider = createDiscreteSlider(['XS', 'S', 'M', 'L', 'XL', 'XXL'], 'single');
document.body.appendChild(sizeSlider);
// Rating range
const ratingSlider = createDiscreteSlider([1, 2, 3, 4, 5], 'range');
document.body.appendChild(ratingSlider);๐จ React-Style Props
import { createSliderWithProps } from '@3nvs/polyfront-slider';
const slider = createSliderWithProps({
mode: 'range',
min: 0,
max: 100,
step: 5,
showTooltip: true,
onChange: (value) => console.log('Value changed:', value),
onInput: (value) => console.log('Value input:', value),
className: 'my-slider',
style: { width: '100%', margin: '20px 0' },
id: 'my-slider'
});
document.body.appendChild(slider);๐ญ Event Handling
const slider = document.getElementById('my-slider');
// Listen for value changes
slider.addEventListener('polyfront-slider-change', (e) => {
console.log('Final value:', e.detail.value);
});
// Listen for real-time input
slider.addEventListener('polyfront-slider-input', (e) => {
console.log('Current value:', e.detail.value);
});
// Get current value
const currentValue = slider.getValue();
console.log('Current value:', currentValue);
// Set value programmatically
slider.setValue([20, 80]); // For range slider
slider.setValue(50); // For single slider๐จ Framework Integration Examples
React
import { useEffect, useRef } from 'react';
import { definePolyfrontSlider, createSliderWithProps } from '@3nvs/polyfront-slider';
// Register once
definePolyfrontSlider();
function PriceSlider({ onChange }: { onChange: (value: number[]) => void }) {
const sliderRef = useRef<HTMLElement>(null);
useEffect(() => {
if (sliderRef.current) {
const slider = createSliderWithProps({
mode: 'range',
min: 0,
max: 2000,
step: 100,
showTooltip: true,
onChange: onChange,
style: { width: '100%' }
});
sliderRef.current.appendChild(slider);
return () => {
sliderRef.current?.removeChild(slider);
};
}
}, [onChange]);
return <div ref={sliderRef} />;
}Vue 3
<template>
<div ref="sliderContainer" />
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { definePolyfrontSlider, createSliderWithProps } from '@3nvs/polyfront-slider';
definePolyfrontSlider();
const sliderContainer = ref<HTMLElement>();
let slider: HTMLElement;
onMounted(() => {
if (sliderContainer.value) {
slider = createSliderWithProps({
mode: 'range',
min: 0,
max: 100,
step: 5,
showTooltip: true,
onChange: (value) => emit('change', value)
});
sliderContainer.value.appendChild(slider);
}
});
onUnmounted(() => {
slider?.remove();
});
const emit = defineEmits<{
change: [value: number[]]
}>();
</script>Angular
import { Component, ElementRef, OnInit, OnDestroy } from '@angular/core';
import { definePolyfrontSlider, createSliderWithProps } from '@3nvs/polyfront-slider';
@Component({
selector: 'app-price-slider',
template: '<div #sliderContainer></div>'
})
export class PriceSliderComponent implements OnInit, OnDestroy {
@ViewChild('sliderContainer', { static: true }) container!: ElementRef;
private slider?: HTMLElement;
ngOnInit() {
definePolyfrontSlider();
this.slider = createSliderWithProps({
mode: 'range',
min: 0,
max: 2000,
step: 100,
showTooltip: true,
onChange: (value) => this.onValueChange(value)
});
this.container.nativeElement.appendChild(this.slider);
}
ngOnDestroy() {
this.slider?.remove();
}
onValueChange(value: number[]) {
console.log('Value changed:', value);
}
}Svelte
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { definePolyfrontSlider, createSliderWithProps } from '@3nvs/polyfront-slider';
let sliderContainer: HTMLElement;
let slider: HTMLElement;
onMount(() => {
definePolyfrontSlider();
slider = createSliderWithProps({
mode: 'range',
min: 0,
max: 100,
step: 5,
showTooltip: true,
onChange: (value) => console.log('Value:', value)
});
sliderContainer.appendChild(slider);
});
onDestroy(() => {
slider?.remove();
});
</script>
<div bind:this={sliderContainer} />โ๏ธ Config Options
| Option | Type | Default | Description |
|---|---|---|---|
mode |
'single' | 'range' |
'single' |
Enables range (2 thumbs) or single thumb. |
orientation |
'horizontal' | 'vertical' |
'horizontal' |
Slider direction. |
size |
'sm' | 'md' | 'lg' |
'md' |
Track and thumb size preset. |
values |
Array<number | string | object> |
โ | Discrete slider values. |
min / max / step |
number |
โ | Continuous slider range. |
disableMissingSteps |
boolean |
true |
Disables non-defined steps. |
blockedIntervals |
[number,number][] |
[] |
Disable ranges of values. |
minThumbDistance |
number |
0 |
Minimum thumb distance in range mode. |
showTicks |
boolean |
false |
Displays tick marks. |
showLabels |
boolean |
false |
Displays tick labels. |
showTooltip |
boolean |
false |
Shows tooltips for thumb values. |
tickEvery |
number |
1 |
Render every N-th tick/label. |
rtl |
boolean |
false |
Right-to-left layout support. |
ariaLabel* |
string |
โ | Accessibility labels. |
name |
string |
โ | Enables form submission via JSON value. |
๐จ Theming & Custom Styles
polyfront-slider {
--pf-color-fill: oklch(0.63 0.21 35);
--pf-color-fill-strong: oklch(0.56 0.22 35);
--pf-color-thumb-border: oklch(0.63 0.21 35);
--pf-track-size: 10px;
--pf-thumb-size: 28px;
--pf-focus: 0 0 0 4px color-mix(in oklab, var(--pf-color-fill) 35%, transparent);
}โ
Supports dark mode (prefers-color-scheme: dark) and reduced motion.
๐งช Testing
npm run testExample:
import { PolyfrontSlider } from '@3nvs/polyfront-slider';
const el = new PolyfrontSlider();
el.setConfig({ min: 0, max: 100, step: 10, mode: 'range' });
el.setValue([20, 80]);
expect(el.getValue()).toEqual([20, 80]);๐ Storybook Demo
Local preview:
npm run storybookLive demo โ https://nirmalsamaranayaka.github.io/polyfront-slider
๐๏ธ Build
npm run buildOutputs:
dist/
โโ index.mjs
โโ index.cjs
โโ index.d.tsโ๏ธ CI / CD via GitHub Actions
| Workflow | Trigger | Purpose |
|---|---|---|
| ci.yml | Push/PR โ main |
Type check, test, build verification |
| storybook.yml | Push โ main |
Deploys Storybook to GitHub Pages |
| release.yml | Tag push (v*.*.*) |
Auto-publishes to npm (requires NPM_TOKEN) |
๐ Folder Structure
polyfront-slider/
โโ dist/ โ build output (from @3nvs/polyfront-slider)
โโ src/
โ โโ index.ts
โ โโ polyfront-slider.ts
โโ tests/ โ Vitest tests
โ โโ polyfront-slider.test.ts
โโ stories/ โ Storybook config
โ โโ polyfront-slider.stories.ts
โโ .storybook/
โโ .github/workflows/ โ CI workflows (ci.yml, storybook.yml, etc.)
โโ tsup.config.ts
โโ tsconfig.json
โโ packages/ โ workspace packages
โ โโ slider/ โ canonical scoped package (@3nvs/polyfront-slider)
โ โ โโ CHANGELOG.md
โ โ โโ package.json
โ โโ slider-shim/ โ unscoped alias (polyfront-slider)
โ โโ CHANGELOG.md
โ โโ index.cjs
โ โโ index.mjs
โ โโ index.d.ts
โ โโ package.json
โโ LICENSE
โโ .npmrc โ optional npm scope config
โโ package.json โ workspace root (private)
โโ README.md๐ Publishing to npm
npm run build
npm version patch
npm publish --access public๐จโ๐ป Author
Nirmal Samaranayaka
๐ง nirmal.fullstack@gmail.com
๐ผ https://github.com/NirmalSamaranayaka
๐ชช License
MIT ยฉ 2025 Nirmal Samaranayaka
See LICENSE for details.