Files
Htmx/docs/Components/Slider.md
T
2026-05-04 19:57:48 +05:00

204 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Slider
A styled `<input type="range">` with optional label and description. Supports min/max/step/value and HTMX attributes.
---
## HTML structure
```
div.flex.flex-col.gap-1.5
label[for={id}].text-sm.font-medium ← omitted when label is empty
{label}
input[type=range, id, name, min, max, step, value, class, $$HxAttrs$$]
p.text-sm.text-muted-foreground ← omitted when description is empty
{description}
```
---
## CSS mechanics
| Class | Effect |
|---|---|
| `w-full h-2 rounded-lg appearance-none cursor-pointer accent-primary` | Full-width, pill-shaped track; thumb follows primary color |
| `bg-secondary` | Track fill color |
| `accent-primary` | Thumb and active track color follows `--color-primary` |
---
## Constructor signature
```csharp
public Slider(
string id,
string name = "",
int min = 0,
int max = 100,
int step = 1,
int value = 50,
string label = "",
string description = "",
string extraClasses = "",
string hxAttrs = "")
```
| Parameter | Description |
|---|---|
| `id` | Element id and label `for` target |
| `name` | Form field name |
| `min` | Minimum value (default: 0) |
| `max` | Maximum value (default: 100) |
| `step` | Increment step (default: 1) |
| `value` | Initial value (default: 50) |
| `label` | Optional visible label |
| `description` | Optional helper text |
| `extraClasses` | Additional Tailwind classes on the input |
| `hxAttrs` | Verbatim HTMX / data attributes |
---
## Usage examples
### Basic 0100 slider
```csharp
new Slider(
id: "volume",
name: "volume",
label: "Volume")
```
### Fixed range with step
```csharp
new Slider(
id: "brightness",
name: "brightness",
min: 10,
max: 100,
step: 10,
value: 70,
label: "Brightness",
description: "10100")
```
### Live HTMX update
```csharp
new Slider(
id: "fontSize",
name: "fontSize",
min: 12,
max: 24,
value: 16,
label: "Font size",
hxAttrs: """hx-post="/settings/font-size" hx-trigger="change" hx-include="[name='fontSize']"""")
```
### Reading in a form handler
```csharp
public record Command([property: FromForm] int Volume);
// command.Volume is the slider value at submit time
```
---
## Tips and tricks
- Display the current numeric value next to the slider by adding a small `<output>` element and a JS `input` event listener: `slider.addEventListener('input', e => output.value = e.target.value)`. This can be added via `hxAttrs: "oninput=\"document.getElementById('vol-val').textContent=this.value\""`.
- `value` is the **initial** server-rendered position. After the user moves the slider, only the form submission captures the new value.
- Use `step` to snap to meaningful increments (e.g. `step: 5` for a 0100 percentage slider).
- `accent-primary` is supported in all modern browsers and requires no custom CSS.
- `accent-primary` is supported in all modern browsers and requires no custom CSS.
---
## Complete page example
**`Templates/AudioSettingsPage.htmx`**
```html
<div class="max-w-md mx-auto py-10">
<h1 class="text-2xl font-bold mb-6">Audio settings</h1>
<form method="post" action="/settings/audio">
$$AntiforgeryToken$$
<div class="space-y-6 mb-8">
$$VolumeSlider$$
$$BassSlider$$
$$TrebleSlider$$
</div>
$$SaveBtn$$
</form>
$$SuccessAlert$$
</div>
```
**`Templates/AudioSettingsPage.htmx.cs`**
```csharp
namespace Htmx.ApiDemo.Templates;
public sealed class AudioSettingsPage : AudioSettingsPageBase
{
private readonly IHtmxComponent _volume;
private readonly IHtmxComponent _bass;
private readonly IHtmxComponent _treble;
private readonly IHtmxComponent _save;
private readonly IHtmxComponent _success;
private readonly byte[] _afToken;
public AudioSettingsPage(
IAntiforgery af,
HttpContext ctx,
AudioPrefs? prefs = null,
bool saved = false)
{
var tokens = af.GetAndStoreTokens(ctx);
_afToken = $"""<input type="hidden" name="{tokens.FormFieldName}" value="{tokens.RequestToken}">""".ToUtf8Bytes();
_volume = new Components.Slider(id: "volume", name: "volume", label: "Volume", value: prefs?.Volume ?? 70, description: "0 100");
_bass = new Components.Slider(id: "bass", name: "bass", label: "Bass", value: prefs?.Bass ?? 50, min: -10, max: 10, step: 1);
_treble = new Components.Slider(id: "treble", name: "treble", label: "Treble", value: prefs?.Treble ?? 50, min: -10, max: 10, step: 1);
_save = new Components.Button("Save", type: "submit");
_success = saved ? new Components.Alert(title: "Audio settings saved.") : HtmxEmpty.Instance;
}
protected override void RenderAntiforgeryToken(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_afToken);
protected override void RenderVolumeSlider(HtmxRenderContext ctx) => _volume.Render(ctx.Next());
protected override void RenderBassSlider(HtmxRenderContext ctx) => _bass.Render(ctx.Next());
protected override void RenderTrebleSlider(HtmxRenderContext ctx) => _treble.Render(ctx.Next());
protected override void RenderSaveBtn(HtmxRenderContext ctx) => _save.Render(ctx.Next());
protected override void RenderSuccessAlert(HtmxRenderContext ctx) => _success.Render(ctx.Next());
}
```
**POST handler**
```csharp
[Handler]
[MapPost("/settings/audio")]
public static partial class PostAudioSettingsHandler
{
public record Command(
[property: FromForm] int Volume,
[property: FromForm] int Bass,
[property: FromForm] int Treble);
private static Task<IResult> HandleAsync(
[AsParameters] Command cmd, HttpContext ctx, IAntiforgery af, CancellationToken ct)
{
var prefs = new AudioPrefs(cmd.Volume, cmd.Bass, cmd.Treble);
// Persist prefs…
return ctx.WriteHtmxPage(
new AudioSettingsPage(af, ctx, prefs, saved: true), title: "Audio settings");
}
}
public record AudioPrefs(int Volume, int Bass, int Treble);
```
**`AppJsonSerializerContext.cs`**
```csharp
[JsonSerializable(typeof(PostAudioSettingsHandler.Command), TypeInfoPropertyName = "AudioSettingsCommand")]
```