Componentresizable
Resizable
Accessible resizable panel groups and layouts with keyboard support.
Preview
Accessible resizable panel groups and layouts with keyboard support.
@ui.ResizablePanelGroup(ui.ResizablePanelGroupProps{DOMProps: ui.DOMProps{Class: "max-w-md rounded-lg border md:min-w-[450px]"}}) {
@ui.ResizablePanel(ui.ResizablePanelProps{DefaultSize: 50}) {
<div class="flex h-[200px] items-center justify-center p-6">
<span class="font-semibold">One</span>
</div>
}
@ui.ResizableHandle(ui.ResizableHandleProps{})
@ui.ResizablePanel(ui.ResizablePanelProps{DefaultSize: 50}) {
<div class="flex h-[200px] items-center justify-center p-6">
<span class="font-semibold">Two</span>
</div>
}
}Installation
Add this component to your project using the CLI.
templcn add resizableUsage
1. Import the component in your Go or templ file:
import "your-module/ui"2. Use the component in your template:
@ui.ResizablePanelGroup(ui.ResizablePanelGroupProps{DOMProps: ui.DOMProps{Class: "max-w-md rounded-lg border md:min-w-[450px]"}}) {
@ui.ResizablePanel(ui.ResizablePanelProps{DefaultSize: 50}) {
<div class="flex h-[200px] items-center justify-center p-6">
<span class="font-semibold">One</span>
</div>
}
@ui.ResizableHandle(ui.ResizableHandleProps{})
@ui.ResizablePanel(ui.ResizablePanelProps{DefaultSize: 50}) {
<div class="flex h-[200px] items-center justify-center p-6">
<span class="font-semibold">Two</span>
</div>
}
}Composition
Use these parts together to build the component.
ResizablePanelGroup
├── ResizablePanel
├── ResizableHandleExamples
Named examples and common variations.
Default
Two resizable panels with a divider handle.
@ui.ResizablePanelGroup(ui.ResizablePanelGroupProps{}) {
@ui.ResizablePanel(ui.ResizablePanelProps{DefaultSize: 50}) { <span>One</span> }
@ui.ResizableHandle(ui.ResizableHandleProps{})
@ui.ResizablePanel(ui.ResizablePanelProps{DefaultSize: 50}) { <span>Two</span> }
}API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| Direction | string | "horizontal" | "horizontal" or "vertical". |
View source
package ui
import (
"context"
"io"
"strconv"
"github.com/a-h/templ"
)
type ResizablePanelGroupProps struct {
DOMProps
Direction string
}
func ResizablePanelGroup(props ResizablePanelGroupProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
attrs := attrsFromDOMProps(props.DOMProps, "resizable-panel-group", "flex h-full w-full aria-[orientation=vertical]:flex-col")
attrs["data-direction"] = "horizontal"
attrs["aria-orientation"] = "horizontal"
if props.Direction != "" {
attrs["data-direction"] = props.Direction
attrs["aria-orientation"] = props.Direction
}
return renderElement(ctx, w, "div", attrs, templ.GetChildren(ctx))
})
}
type ResizablePanelProps struct {
DOMProps
DefaultSize float64
MinSize float64
MaxSize float64
Collapsible bool
}
func ResizablePanel(props ResizablePanelProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
attrs := attrsFromDOMProps(props.DOMProps, "resizable-panel", "min-h-0 min-w-0")
size := props.DefaultSize
if size <= 0 {
size = 50
}
attrs["data-size"] = size
attrs["style"] = "flex-basis: " + strconv.FormatFloat(size, 'f', -1, 64) + "%"
if props.DefaultSize > 0 {
attrs["data-default-size"] = props.DefaultSize
}
if props.MinSize > 0 {
attrs["data-min-size"] = props.MinSize
}
if props.MaxSize > 0 {
attrs["data-max-size"] = props.MaxSize
}
if props.Collapsible {
attrs["data-collapsible"] = "true"
}
return renderElement(ctx, w, "div", attrs, templ.GetChildren(ctx))
})
}
type ResizableHandleProps struct {
DOMProps
WithHandle bool
}
func ResizableHandle(props ResizableHandleProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
attrs := attrsFromDOMProps(props.DOMProps, "resizable-handle", "relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90")
attrs["role"] = "separator"
attrs["tabindex"] = "0"
attrs["aria-orientation"] = "vertical"
if props.WithHandle {
attrs["data-with-handle"] = "true"
}
children := templ.GetChildren(ctx)
if props.WithHandle && children == nil {
children = templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
icon := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
_, err := io.WriteString(w, `<svg xmlns="http://www.w3.org/2000/svg" class="size-2.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="12" r="1"></circle><circle cx="9" cy="5" r="1"></circle><circle cx="9" cy="19" r="1"></circle><circle cx="15" cy="12" r="1"></circle><circle cx="15" cy="5" r="1"></circle><circle cx="15" cy="19" r="1"></circle></svg>`)
return err
})
return renderElement(ctx, w, "div", templ.Attributes{"class": "z-10 flex h-4 w-3 items-center justify-center rounded-xs border bg-border"}, icon)
})
}
return renderElement(ctx, w, "div", attrs, children)
})
}