General
Range code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/range.blade.php
@props([
'name' => null,
'value' => 50,
'min' => 0,
'max' => 100,
'step' => 1,
'showValue' => false,
'prefix' => '',
'suffix' => '',
'disabled' => false,
])
@php
/*
| Range slider with a brand-colored filled track and optional live value
| bubble. The fill is driven by Alpine so it works across browsers.
|
| Usage:
| <x-ui.range name="volume" :value="40" show-value suffix="%" />
| <x-ui.range name="price" :min="0" :max="500" :step="10" :value="250" prefix="$" show-value />
*/
$min = (float) $min;
$max = (float) $max;
$normalizedName = $name
? trim((string) preg_replace('/[^A-Za-z0-9\-_:.]+/', '-', str_replace(['[', ']'], '', (string) $name)), '-')
: null;
$inputId = $attributes->get('id') ?: $normalizedName;
$providedAriaLabel = $attributes->get('aria-label');
$providedAriaLabelledBy = $attributes->get('aria-labelledby');
$fallbackLabel = null;
if (! $providedAriaLabel && ! $providedAriaLabelledBy && ! $attributes->get('id')) {
$fallbackLabel = $name
? Str::headline(str_replace(['-', '_'], ' ', $normalizedName ?? (string) $name))
: 'Range slider';
}
@endphp
<div
x-data="{
value: @js((float) $value),
min: @js($min),
max: @js($max),
get percent() {
return this.max > this.min ? ((this.value - this.min) / (this.max - this.min)) * 100 : 0;
},
}"
{{ $attributes->only('class')->merge(['class' => 'w-full']) }}
>
@if ($showValue)
<div class="mb-2 flex items-center justify-between text-sm">
<span class="font-medium text-gray-700 dark:text-gray-300">{{ $prefix }}<span x-text="value"></span>{{ $suffix }}</span>
</div>
@endif
<input
type="range"
@if ($name) name="{{ $name }}" @endif
@if ($inputId) id="{{ $inputId }}" @endif
@if ($fallbackLabel) aria-label="{{ $fallbackLabel }}" @endif
min="{{ $min }}"
max="{{ $max }}"
step="{{ $step }}"
x-model="value"
@disabled($disabled)
:style="`background: linear-gradient(to right, var(--color-brand-600) ${percent}%, var(--color-gray-200) ${percent}%)`"
class="h-2 w-full cursor-pointer appearance-none rounded-full bg-gray-200 dark:bg-gray-800 outline-none transition disabled:opacity-50 disabled:cursor-not-allowed
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-brand-600 [&::-webkit-slider-thumb]:shadow [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:transition
[&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-brand-600 [&::-moz-range-thumb]:shadow [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-track]:bg-transparent"
{{ $attributes->except(['class', 'id', 'aria-label']) }}
>
</div>