Spinner
Visual indicators for loading states and processes in progress.
TailwindCSS
package showcase
import "github.com/axzilla/templui/components"
templ SpinnerDefault() {
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeMd,
})
}
package components
import "github.com/axzilla/templui/utils"
type SpinnerSize string
const (
SpinnerSizeSm SpinnerSize = "sm"
SpinnerSizeMd SpinnerSize = "md"
SpinnerSizeLg SpinnerSize = "lg"
)
type SpinnerProps struct {
ID string
Class string
Attributes templ.Attributes
Size SpinnerSize
Color string
}
templ Spinner(props ...SpinnerProps) {
{{ var p SpinnerProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex flex-col items-center justify-center",
p.Class,
),
}
aria-label="Loading"
role="status"
{ p.Attributes... }
>
<div
class={
utils.TwMerge(
"animate-spin rounded-full",
spinnerSizeClass(p.Size),
borderSpinnerClass(p.Size),
utils.IfElse(
p.Color == "",
"border-primary border-b-transparent",
"border-current border-b-transparent",
),
utils.IfElse(
p.Color != "",
p.Color,
"",
),
),
}
></div>
</div>
}
func spinnerSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "w-6 h-6"
case SpinnerSizeLg:
return "w-12 h-12"
default:
return "w-8 h-8"
}
}
func borderSpinnerClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "border-[3px]"
case SpinnerSizeLg:
return "border-[5px]"
default:
return "border-4"
}
}
func textSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "text-sm"
case SpinnerSizeLg:
return "text-lg"
default:
return "text-base"
}
}
Usage
@components.Spinner(components.SpinnerProps{...})
Examples
Sizes
package showcase
import "github.com/axzilla/templui/components"
templ SpinnerSizes() {
<div class="flex flex-wrap items-end justify-center gap-8">
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeSm,
})
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeMd,
})
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeLg,
})
</div>
}
package components
import "github.com/axzilla/templui/utils"
type SpinnerSize string
const (
SpinnerSizeSm SpinnerSize = "sm"
SpinnerSizeMd SpinnerSize = "md"
SpinnerSizeLg SpinnerSize = "lg"
)
type SpinnerProps struct {
ID string
Class string
Attributes templ.Attributes
Size SpinnerSize
Color string
}
templ Spinner(props ...SpinnerProps) {
{{ var p SpinnerProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex flex-col items-center justify-center",
p.Class,
),
}
aria-label="Loading"
role="status"
{ p.Attributes... }
>
<div
class={
utils.TwMerge(
"animate-spin rounded-full",
spinnerSizeClass(p.Size),
borderSpinnerClass(p.Size),
utils.IfElse(
p.Color == "",
"border-primary border-b-transparent",
"border-current border-b-transparent",
),
utils.IfElse(
p.Color != "",
p.Color,
"",
),
),
}
></div>
</div>
}
func spinnerSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "w-6 h-6"
case SpinnerSizeLg:
return "w-12 h-12"
default:
return "w-8 h-8"
}
}
func borderSpinnerClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "border-[3px]"
case SpinnerSizeLg:
return "border-[5px]"
default:
return "border-4"
}
}
func textSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "text-sm"
case SpinnerSizeLg:
return "text-lg"
default:
return "text-base"
}
}
Colors
package showcase
import "github.com/axzilla/templui/components"
templ SpinnerColors() {
<div class="flex flex-wrap items-end justify-center gap-8">
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeMd,
Color: "text-red-500",
})
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeMd,
Color: "text-green-500",
})
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeMd,
Color: "text-blue-500",
})
</div>
}
package components
import "github.com/axzilla/templui/utils"
type SpinnerSize string
const (
SpinnerSizeSm SpinnerSize = "sm"
SpinnerSizeMd SpinnerSize = "md"
SpinnerSizeLg SpinnerSize = "lg"
)
type SpinnerProps struct {
ID string
Class string
Attributes templ.Attributes
Size SpinnerSize
Color string
}
templ Spinner(props ...SpinnerProps) {
{{ var p SpinnerProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex flex-col items-center justify-center",
p.Class,
),
}
aria-label="Loading"
role="status"
{ p.Attributes... }
>
<div
class={
utils.TwMerge(
"animate-spin rounded-full",
spinnerSizeClass(p.Size),
borderSpinnerClass(p.Size),
utils.IfElse(
p.Color == "",
"border-primary border-b-transparent",
"border-current border-b-transparent",
),
utils.IfElse(
p.Color != "",
p.Color,
"",
),
),
}
></div>
</div>
}
func spinnerSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "w-6 h-6"
case SpinnerSizeLg:
return "w-12 h-12"
default:
return "w-8 h-8"
}
}
func borderSpinnerClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "border-[3px]"
case SpinnerSizeLg:
return "border-[5px]"
default:
return "border-4"
}
}
func textSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "text-sm"
case SpinnerSizeLg:
return "text-lg"
default:
return "text-base"
}
}
In Button
package showcase
import "github.com/axzilla/templui/components"
templ SpinnerInButton() {
@components.Button(components.ButtonProps{
Attributes: templ.Attributes{
"disabled": "true",
},
}) {
<div class="flex items-center gap-2">
@components.Spinner(components.SpinnerProps{
Size: components.SpinnerSizeSm,
Color: "text-primary-foreground",
})
<span>Loading</span>
</div>
}
}
package components
import "github.com/axzilla/templui/utils"
type SpinnerSize string
const (
SpinnerSizeSm SpinnerSize = "sm"
SpinnerSizeMd SpinnerSize = "md"
SpinnerSizeLg SpinnerSize = "lg"
)
type SpinnerProps struct {
ID string
Class string
Attributes templ.Attributes
Size SpinnerSize
Color string
}
templ Spinner(props ...SpinnerProps) {
{{ var p SpinnerProps }}
if len(props) > 0 {
{{ p = props[0] }}
}
<div
if p.ID != "" {
id={ p.ID }
}
class={
utils.TwMerge(
"inline-flex flex-col items-center justify-center",
p.Class,
),
}
aria-label="Loading"
role="status"
{ p.Attributes... }
>
<div
class={
utils.TwMerge(
"animate-spin rounded-full",
spinnerSizeClass(p.Size),
borderSpinnerClass(p.Size),
utils.IfElse(
p.Color == "",
"border-primary border-b-transparent",
"border-current border-b-transparent",
),
utils.IfElse(
p.Color != "",
p.Color,
"",
),
),
}
></div>
</div>
}
func spinnerSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "w-6 h-6"
case SpinnerSizeLg:
return "w-12 h-12"
default:
return "w-8 h-8"
}
}
func borderSpinnerClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "border-[3px]"
case SpinnerSizeLg:
return "border-[5px]"
default:
return "border-4"
}
}
func textSizeClass(size SpinnerSize) string {
switch size {
case SpinnerSizeSm:
return "text-sm"
case SpinnerSizeLg:
return "text-lg"
default:
return "text-base"
}
}