Slider
Control for selecting a numeric value within a range.
TailwindCSS
Alpine.js
package showcase
import "github.com/axzilla/templui/pkg/components"
templ SliderDefault() {
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "default",
Name: "default",
})
</div>
}
package components
type SheetSide string
const (
SheetSideTop SheetSide = "top"
SheetSideRight SheetSide = "right"
SheetSideBottom SheetSide = "bottom"
SheetSideLeft SheetSide = "left"
)
type SheetProps struct {
Title string // Header text
Description string // Subheading text
Side SheetSide // Slide-in direction
}
templ SheetScript() {
{{ handle := templ.NewOnceHandle() }}
@handle.Once() {
<script nonce={ templ.GetNonce(ctx) }>
document.addEventListener('alpine:init', () => {
Alpine.data('sheet', () => ({
isOpen: false,
open() {
this.isOpen = true
},
close() {
this.isOpen = false
},
}))
})
</script>
}
}
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
templ SheetRoot() {
<div
x-data="sheet"
@keydown.escape.window="close"
>
{ children... }
</div>
}
// Side-anchored panel that slides in from screen edges.
templ Sheet(props SheetProps) {
<!-- Backdrop -->
<div
x-show="isOpen"
class="fixed inset-0 bg-background/80 backdrop-blur-sm"
@click="close"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
<!-- Sheet -->
<div
x-show="isOpen"
class={
"z-50",
templ.KV("fixed inset-y-0 right-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideRight),
templ.KV("fixed inset-y-0 left-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideLeft),
templ.KV("fixed inset-x-0 top-0 h-auto sm:h-1/2", props.Side == SheetSideTop),
templ.KV("fixed inset-x-0 bottom-0 h-auto sm:h-1/2", props.Side == SheetSideBottom),
}
x-transition:enter="transition ease-out duration-300"
x-transition:leave="transition ease-in duration-300"
if props.Side == SheetSideLeft {
x-transition:enter-start="opacity-0 transform -translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform -translate-x-full"
}
if props.Side == SheetSideRight {
x-transition:enter-start="opacity-0 transform translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform translate-x-full"
}
if props.Side == SheetSideTop {
x-transition:enter-start="opacity-0 transform -translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform -translate-y-full"
}
if props.Side == SheetSideBottom {
x-transition:enter-start="opacity-0 transform translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-full"
}
>
<div
class={ "h-full overflow-y-auto bg-background p-6 shadow-lg",
templ.KV("border-l", props.Side == SheetSideRight),
templ.KV("border-r", props.Side == SheetSideLeft),
templ.KV("border-t", props.Side == SheetSideBottom),
templ.KV("border-b", props.Side == SheetSideTop) }
>
<div class="flex flex-col space-y-2">
<h2 class="text-lg font-semibold">{ props.Title }</h2>
<p class="text-sm text-muted-foreground">{ props.Description }</p>
</div>
<div class="mt-4">
{ children... }
</div>
</div>
</div>
}
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
templ SheetTrigger(text string, side SheetSide) {
<span @click="open">
{ children... }
</span>
}
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
templ SheetClose(text string) {
<button
@click="close"
class={ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background",
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent",
"hover:text-accent-foreground h-10 px-4 py-2" }
>
{ text }
</button>
}
Usage
1. Add the script to your page/layout:
// Option A: All components (recommended)
@utils.ComponentScripts()
// Option B: Just Slider
@components.SliderScript()
2. Use the component:
@components.Slider(components.SliderProps{...})
Examples
With Value
%
package showcase
import "github.com/axzilla/templui/pkg/components"
templ SliderWithValue() {
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "with-label",
Name: "with-label",
Value: 75,
Min: 0,
Max: 100,
Step: 1,
ShowValue: true,
ValueFormat: "%",
})
</div>
}
package components
type SheetSide string
const (
SheetSideTop SheetSide = "top"
SheetSideRight SheetSide = "right"
SheetSideBottom SheetSide = "bottom"
SheetSideLeft SheetSide = "left"
)
type SheetProps struct {
Title string // Header text
Description string // Subheading text
Side SheetSide // Slide-in direction
}
templ SheetScript() {
{{ handle := templ.NewOnceHandle() }}
@handle.Once() {
<script nonce={ templ.GetNonce(ctx) }>
document.addEventListener('alpine:init', () => {
Alpine.data('sheet', () => ({
isOpen: false,
open() {
this.isOpen = true
},
close() {
this.isOpen = false
},
}))
})
</script>
}
}
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
templ SheetRoot() {
<div
x-data="sheet"
@keydown.escape.window="close"
>
{ children... }
</div>
}
// Side-anchored panel that slides in from screen edges.
templ Sheet(props SheetProps) {
<!-- Backdrop -->
<div
x-show="isOpen"
class="fixed inset-0 bg-background/80 backdrop-blur-sm"
@click="close"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
<!-- Sheet -->
<div
x-show="isOpen"
class={
"z-50",
templ.KV("fixed inset-y-0 right-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideRight),
templ.KV("fixed inset-y-0 left-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideLeft),
templ.KV("fixed inset-x-0 top-0 h-auto sm:h-1/2", props.Side == SheetSideTop),
templ.KV("fixed inset-x-0 bottom-0 h-auto sm:h-1/2", props.Side == SheetSideBottom),
}
x-transition:enter="transition ease-out duration-300"
x-transition:leave="transition ease-in duration-300"
if props.Side == SheetSideLeft {
x-transition:enter-start="opacity-0 transform -translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform -translate-x-full"
}
if props.Side == SheetSideRight {
x-transition:enter-start="opacity-0 transform translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform translate-x-full"
}
if props.Side == SheetSideTop {
x-transition:enter-start="opacity-0 transform -translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform -translate-y-full"
}
if props.Side == SheetSideBottom {
x-transition:enter-start="opacity-0 transform translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-full"
}
>
<div
class={ "h-full overflow-y-auto bg-background p-6 shadow-lg",
templ.KV("border-l", props.Side == SheetSideRight),
templ.KV("border-r", props.Side == SheetSideLeft),
templ.KV("border-t", props.Side == SheetSideBottom),
templ.KV("border-b", props.Side == SheetSideTop) }
>
<div class="flex flex-col space-y-2">
<h2 class="text-lg font-semibold">{ props.Title }</h2>
<p class="text-sm text-muted-foreground">{ props.Description }</p>
</div>
<div class="mt-4">
{ children... }
</div>
</div>
</div>
}
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
templ SheetTrigger(text string, side SheetSide) {
<span @click="open">
{ children... }
</span>
}
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
templ SheetClose(text string) {
<button
@click="close"
class={ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background",
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent",
"hover:text-accent-foreground h-10 px-4 py-2" }
>
{ text }
</button>
}
With Label
package showcase
import "github.com/axzilla/templui/pkg/components"
templ SliderWithLabel() {
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "with-label",
Name: "with-label",
Label: "Volume",
Value: 65,
Min: 0,
Max: 100,
Step: 1,
})
</div>
}
package components
type SheetSide string
const (
SheetSideTop SheetSide = "top"
SheetSideRight SheetSide = "right"
SheetSideBottom SheetSide = "bottom"
SheetSideLeft SheetSide = "left"
)
type SheetProps struct {
Title string // Header text
Description string // Subheading text
Side SheetSide // Slide-in direction
}
templ SheetScript() {
{{ handle := templ.NewOnceHandle() }}
@handle.Once() {
<script nonce={ templ.GetNonce(ctx) }>
document.addEventListener('alpine:init', () => {
Alpine.data('sheet', () => ({
isOpen: false,
open() {
this.isOpen = true
},
close() {
this.isOpen = false
},
}))
})
</script>
}
}
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
templ SheetRoot() {
<div
x-data="sheet"
@keydown.escape.window="close"
>
{ children... }
</div>
}
// Side-anchored panel that slides in from screen edges.
templ Sheet(props SheetProps) {
<!-- Backdrop -->
<div
x-show="isOpen"
class="fixed inset-0 bg-background/80 backdrop-blur-sm"
@click="close"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
<!-- Sheet -->
<div
x-show="isOpen"
class={
"z-50",
templ.KV("fixed inset-y-0 right-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideRight),
templ.KV("fixed inset-y-0 left-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideLeft),
templ.KV("fixed inset-x-0 top-0 h-auto sm:h-1/2", props.Side == SheetSideTop),
templ.KV("fixed inset-x-0 bottom-0 h-auto sm:h-1/2", props.Side == SheetSideBottom),
}
x-transition:enter="transition ease-out duration-300"
x-transition:leave="transition ease-in duration-300"
if props.Side == SheetSideLeft {
x-transition:enter-start="opacity-0 transform -translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform -translate-x-full"
}
if props.Side == SheetSideRight {
x-transition:enter-start="opacity-0 transform translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform translate-x-full"
}
if props.Side == SheetSideTop {
x-transition:enter-start="opacity-0 transform -translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform -translate-y-full"
}
if props.Side == SheetSideBottom {
x-transition:enter-start="opacity-0 transform translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-full"
}
>
<div
class={ "h-full overflow-y-auto bg-background p-6 shadow-lg",
templ.KV("border-l", props.Side == SheetSideRight),
templ.KV("border-r", props.Side == SheetSideLeft),
templ.KV("border-t", props.Side == SheetSideBottom),
templ.KV("border-b", props.Side == SheetSideTop) }
>
<div class="flex flex-col space-y-2">
<h2 class="text-lg font-semibold">{ props.Title }</h2>
<p class="text-sm text-muted-foreground">{ props.Description }</p>
</div>
<div class="mt-4">
{ children... }
</div>
</div>
</div>
}
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
templ SheetTrigger(text string, side SheetSide) {
<span @click="open">
{ children... }
</span>
}
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
templ SheetClose(text string) {
<button
@click="close"
class={ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background",
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent",
"hover:text-accent-foreground h-10 px-4 py-2" }
>
{ text }
</button>
}
With Steps
%
package showcase
import "github.com/axzilla/templui/pkg/components"
templ SliderWithSteps() {
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "steps",
Name: "steps",
Label: "Zoom Level",
Value: 100,
Min: 0,
Max: 200,
Step: 25,
ShowValue: true,
ValueFormat: "%",
})
</div>
}
package components
type SheetSide string
const (
SheetSideTop SheetSide = "top"
SheetSideRight SheetSide = "right"
SheetSideBottom SheetSide = "bottom"
SheetSideLeft SheetSide = "left"
)
type SheetProps struct {
Title string // Header text
Description string // Subheading text
Side SheetSide // Slide-in direction
}
templ SheetScript() {
{{ handle := templ.NewOnceHandle() }}
@handle.Once() {
<script nonce={ templ.GetNonce(ctx) }>
document.addEventListener('alpine:init', () => {
Alpine.data('sheet', () => ({
isOpen: false,
open() {
this.isOpen = true
},
close() {
this.isOpen = false
},
}))
})
</script>
}
}
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
templ SheetRoot() {
<div
x-data="sheet"
@keydown.escape.window="close"
>
{ children... }
</div>
}
// Side-anchored panel that slides in from screen edges.
templ Sheet(props SheetProps) {
<!-- Backdrop -->
<div
x-show="isOpen"
class="fixed inset-0 bg-background/80 backdrop-blur-sm"
@click="close"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
<!-- Sheet -->
<div
x-show="isOpen"
class={
"z-50",
templ.KV("fixed inset-y-0 right-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideRight),
templ.KV("fixed inset-y-0 left-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideLeft),
templ.KV("fixed inset-x-0 top-0 h-auto sm:h-1/2", props.Side == SheetSideTop),
templ.KV("fixed inset-x-0 bottom-0 h-auto sm:h-1/2", props.Side == SheetSideBottom),
}
x-transition:enter="transition ease-out duration-300"
x-transition:leave="transition ease-in duration-300"
if props.Side == SheetSideLeft {
x-transition:enter-start="opacity-0 transform -translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform -translate-x-full"
}
if props.Side == SheetSideRight {
x-transition:enter-start="opacity-0 transform translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform translate-x-full"
}
if props.Side == SheetSideTop {
x-transition:enter-start="opacity-0 transform -translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform -translate-y-full"
}
if props.Side == SheetSideBottom {
x-transition:enter-start="opacity-0 transform translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-full"
}
>
<div
class={ "h-full overflow-y-auto bg-background p-6 shadow-lg",
templ.KV("border-l", props.Side == SheetSideRight),
templ.KV("border-r", props.Side == SheetSideLeft),
templ.KV("border-t", props.Side == SheetSideBottom),
templ.KV("border-b", props.Side == SheetSideTop) }
>
<div class="flex flex-col space-y-2">
<h2 class="text-lg font-semibold">{ props.Title }</h2>
<p class="text-sm text-muted-foreground">{ props.Description }</p>
</div>
<div class="mt-4">
{ children... }
</div>
</div>
</div>
}
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
templ SheetTrigger(text string, side SheetSide) {
<span @click="open">
{ children... }
</span>
}
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
templ SheetClose(text string) {
<button
@click="close"
class={ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background",
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent",
"hover:text-accent-foreground h-10 px-4 py-2" }
>
{ text }
</button>
}
With Label and Value
°C
package showcase
import "github.com/axzilla/templui/pkg/components"
templ SliderWithLabelAndValue() {
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "temperature",
Name: "temperature",
Label: "Temperature",
Value: 23,
Min: -20,
Max: 40,
Step: 1,
ShowValue: true,
ValueFormat: "°C",
})
</div>
}
package components
type SheetSide string
const (
SheetSideTop SheetSide = "top"
SheetSideRight SheetSide = "right"
SheetSideBottom SheetSide = "bottom"
SheetSideLeft SheetSide = "left"
)
type SheetProps struct {
Title string // Header text
Description string // Subheading text
Side SheetSide // Slide-in direction
}
templ SheetScript() {
{{ handle := templ.NewOnceHandle() }}
@handle.Once() {
<script nonce={ templ.GetNonce(ctx) }>
document.addEventListener('alpine:init', () => {
Alpine.data('sheet', () => ({
isOpen: false,
open() {
this.isOpen = true
},
close() {
this.isOpen = false
},
}))
})
</script>
}
}
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
templ SheetRoot() {
<div
x-data="sheet"
@keydown.escape.window="close"
>
{ children... }
</div>
}
// Side-anchored panel that slides in from screen edges.
templ Sheet(props SheetProps) {
<!-- Backdrop -->
<div
x-show="isOpen"
class="fixed inset-0 bg-background/80 backdrop-blur-sm"
@click="close"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
<!-- Sheet -->
<div
x-show="isOpen"
class={
"z-50",
templ.KV("fixed inset-y-0 right-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideRight),
templ.KV("fixed inset-y-0 left-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideLeft),
templ.KV("fixed inset-x-0 top-0 h-auto sm:h-1/2", props.Side == SheetSideTop),
templ.KV("fixed inset-x-0 bottom-0 h-auto sm:h-1/2", props.Side == SheetSideBottom),
}
x-transition:enter="transition ease-out duration-300"
x-transition:leave="transition ease-in duration-300"
if props.Side == SheetSideLeft {
x-transition:enter-start="opacity-0 transform -translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform -translate-x-full"
}
if props.Side == SheetSideRight {
x-transition:enter-start="opacity-0 transform translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform translate-x-full"
}
if props.Side == SheetSideTop {
x-transition:enter-start="opacity-0 transform -translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform -translate-y-full"
}
if props.Side == SheetSideBottom {
x-transition:enter-start="opacity-0 transform translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-full"
}
>
<div
class={ "h-full overflow-y-auto bg-background p-6 shadow-lg",
templ.KV("border-l", props.Side == SheetSideRight),
templ.KV("border-r", props.Side == SheetSideLeft),
templ.KV("border-t", props.Side == SheetSideBottom),
templ.KV("border-b", props.Side == SheetSideTop) }
>
<div class="flex flex-col space-y-2">
<h2 class="text-lg font-semibold">{ props.Title }</h2>
<p class="text-sm text-muted-foreground">{ props.Description }</p>
</div>
<div class="mt-4">
{ children... }
</div>
</div>
</div>
}
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
templ SheetTrigger(text string, side SheetSide) {
<span @click="open">
{ children... }
</span>
}
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
templ SheetClose(text string) {
<button
@click="close"
class={ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background",
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent",
"hover:text-accent-foreground h-10 px-4 py-2" }
>
{ text }
</button>
}
Disabled
package showcase
import "github.com/axzilla/templui/pkg/components"
templ SliderDisabled() {
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "disabled",
Name: "disabled",
Label: "Disabled Slider",
Value: 20,
Min: -20,
Max: 200,
Step: 20,
Disabled: true,
ShowValue: true,
})
</div>
}
package components
type SheetSide string
const (
SheetSideTop SheetSide = "top"
SheetSideRight SheetSide = "right"
SheetSideBottom SheetSide = "bottom"
SheetSideLeft SheetSide = "left"
)
type SheetProps struct {
Title string // Header text
Description string // Subheading text
Side SheetSide // Slide-in direction
}
templ SheetScript() {
{{ handle := templ.NewOnceHandle() }}
@handle.Once() {
<script nonce={ templ.GetNonce(ctx) }>
document.addEventListener('alpine:init', () => {
Alpine.data('sheet', () => ({
isOpen: false,
open() {
this.isOpen = true
},
close() {
this.isOpen = false
},
}))
})
</script>
}
}
// SheetRoot initializes Alpine.js state and event handlers
// Must wrap Sheet components and triggers
templ SheetRoot() {
<div
x-data="sheet"
@keydown.escape.window="close"
>
{ children... }
</div>
}
// Side-anchored panel that slides in from screen edges.
templ Sheet(props SheetProps) {
<!-- Backdrop -->
<div
x-show="isOpen"
class="fixed inset-0 bg-background/80 backdrop-blur-sm"
@click="close"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
></div>
<!-- Sheet -->
<div
x-show="isOpen"
class={
"z-50",
templ.KV("fixed inset-y-0 right-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideRight),
templ.KV("fixed inset-y-0 left-0 w-3/4 md:w-1/2 lg:w-1/3", props.Side == SheetSideLeft),
templ.KV("fixed inset-x-0 top-0 h-auto sm:h-1/2", props.Side == SheetSideTop),
templ.KV("fixed inset-x-0 bottom-0 h-auto sm:h-1/2", props.Side == SheetSideBottom),
}
x-transition:enter="transition ease-out duration-300"
x-transition:leave="transition ease-in duration-300"
if props.Side == SheetSideLeft {
x-transition:enter-start="opacity-0 transform -translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform -translate-x-full"
}
if props.Side == SheetSideRight {
x-transition:enter-start="opacity-0 transform translate-x-full"
x-transition:enter-end="opacity-100 transform translate-x-0"
x-transition:leave-start="opacity-100 transform translate-x-0"
x-transition:leave-end="opacity-0 transform translate-x-full"
}
if props.Side == SheetSideTop {
x-transition:enter-start="opacity-0 transform -translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform -translate-y-full"
}
if props.Side == SheetSideBottom {
x-transition:enter-start="opacity-0 transform translate-y-full"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-full"
}
>
<div
class={ "h-full overflow-y-auto bg-background p-6 shadow-lg",
templ.KV("border-l", props.Side == SheetSideRight),
templ.KV("border-r", props.Side == SheetSideLeft),
templ.KV("border-t", props.Side == SheetSideBottom),
templ.KV("border-b", props.Side == SheetSideTop) }
>
<div class="flex flex-col space-y-2">
<h2 class="text-lg font-semibold">{ props.Title }</h2>
<p class="text-sm text-muted-foreground">{ props.Description }</p>
</div>
<div class="mt-4">
{ children... }
</div>
</div>
</div>
}
// SheetTrigger creates elements that open the sheet
// Must be used within SheetRoot
templ SheetTrigger(text string, side SheetSide) {
<span @click="open">
{ children... }
</span>
}
// SheetClose creates a button that closes the sheet
// Must be used within Sheet
templ SheetClose(text string) {
<button
@click="close"
class={ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background",
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent",
"hover:text-accent-foreground h-10 px-4 py-2" }
>
{ text }
</button>
}