Empty
A placeholder for an empty result.
<empty.Empty>
<empty.EmptyHeader>
<empty.EmptyMedia variant={empty.Icon}><icons.Info /></empty.EmptyMedia>
<empty.EmptyTitle>No projects</empty.EmptyTitle>
<empty.EmptyDescription>Create your first project to start.</empty.EmptyDescription>
</empty.EmptyHeader>
<empty.EmptyContent><button.Button>New project</button.Button></empty.EmptyContent>
</empty.Empty>Installation
Run the command in the app module.
gx add emptyThe command also installs button and icons.
The command writes these files.
| File | Path in the app |
|---|---|
Empty.gx |
ui/empty/Empty.gx |
EmptyHeader.gx |
ui/empty/EmptyHeader.gx |
EmptyTitle.gx |
ui/empty/EmptyTitle.gx |
EmptyDescription.gx |
ui/empty/EmptyDescription.gx |
EmptyContent.gx |
ui/empty/EmptyContent.gx |
EmptyMedia.gx |
ui/empty/EmptyMedia.gx |
Empty.fixtures.go |
ui/empty/Empty.fixtures.go |
styles.go |
ui/empty/styles.go |
EmptyContent.fixtures.go |
ui/empty/EmptyContent.fixtures.go |
EmptyDescription.fixtures.go |
ui/empty/EmptyDescription.fixtures.go |
EmptyHeader.fixtures.go |
ui/empty/EmptyHeader.fixtures.go |
EmptyMedia.fixtures.go |
ui/empty/EmptyMedia.fixtures.go |
EmptyTitle.fixtures.go |
ui/empty/EmptyTitle.fixtures.go |
Install button and icons first.
Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.
package empty
props {
// Class adds classes to the root element.
Class string = ""
// Children is the content of the empty state.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div data-slot="empty" class={gx.Cx("flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12", p.Class)} {...p.Attrs}>{p.Children}</div>package empty
props {
// Class adds classes to the root element.
Class string = ""
// Children is the content of the header: the media, the title and the description.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div data-slot="empty-header" class={gx.Cx("flex max-w-sm flex-col items-center gap-2 text-center", p.Class)} {...p.Attrs}>{p.Children}</div>package empty
props {
// Class adds classes to the root element.
Class string = ""
// Children is the title text.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div data-slot="empty-title" class={gx.Cx("text-lg font-medium tracking-tight", p.Class)} {...p.Attrs}>{p.Children}</div>package empty
props {
// Class adds classes to the root element.
Class string = ""
// Children is the description text.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div data-slot="empty-description" class={gx.Cx("text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", p.Class)} {...p.Attrs}>{p.Children}</div>package empty
props {
// Class adds classes to the root element.
Class string = ""
// Children is the content below the header, for example the actions.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div data-slot="empty-content" class={gx.Cx("flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance", p.Class)} {...p.Attrs}>{p.Children}</div>package empty
props {
// Variant sets the look of the media: Default or Icon. Icon draws a muted rounded box.
Variant Variant = Default
// Class adds classes to the root element.
Class string = ""
// Children is the media, for example an icon.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div data-slot="empty-icon" data-variant={p.variant()} class={gx.Cx("mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", variantClass[Variant(p.variant())], p.Class)} {...p.Attrs}>{p.Children}</div>package empty
import (
"github.com/alternayte/gx"
"github.com/alternayte/gx/registry/button"
"github.com/alternayte/gx/registry/icons"
)
var EmptyFixtures = gx.Fixtures[EmptyProps]{
"Full": {Children: gx.Frag(
EmptyHeader(EmptyHeaderProps{Children: gx.Frag(
EmptyMedia(EmptyMediaProps{Variant: Icon, Children: icons.Info(icons.InfoProps{})}),
EmptyTitle(EmptyTitleProps{Children: gx.Text("No projects")}),
EmptyDescription(EmptyDescriptionProps{Children: gx.Text("Create your first project to start.")}),
)}),
EmptyContent(EmptyContentProps{Children: button.Button(button.ButtonProps{Children: gx.Text("New project")})}),
)},
"Outline": {Class: "border", Children: EmptyHeader(EmptyHeaderProps{Children: gx.Frag(
EmptyTitle(EmptyTitleProps{Children: gx.Text("No results")}),
EmptyDescription(EmptyDescriptionProps{Children: gx.Text("Change the filter and search again.")}),
)})},
}package empty
import "github.com/alternayte/gx"
// Variant is the look of the media slot of an empty state.
type Variant string
// The variants of empty.EmptyMedia.
const (
Default Variant = "default"
Icon Variant = "icon"
)
var variantClass = gx.Enum[Variant]{
Default: "bg-transparent",
Icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6",
}
// variant returns the data-variant value; a zero value is Default.
func (p EmptyMediaProps) variant() string {
if p.Variant == "" {
return string(Default)
}
return string(p.Variant)
}package empty
import "github.com/alternayte/gx"
var EmptyContentFixtures = gx.Fixtures[EmptyContentProps]{"Empty": {}}package empty
import "github.com/alternayte/gx"
var EmptyDescriptionFixtures = gx.Fixtures[EmptyDescriptionProps]{"Text": {Children: gx.Text("Create your first project.")}}package empty
import "github.com/alternayte/gx"
var EmptyHeaderFixtures = gx.Fixtures[EmptyHeaderProps]{"Empty": {}}package empty
import (
"github.com/alternayte/gx"
"github.com/alternayte/gx/registry/icons"
)
var EmptyMediaFixtures = gx.Fixtures[EmptyMediaProps]{
"Icon": {Variant: Icon, Children: icons.Info(icons.InfoProps{})},
"Default": {Children: icons.Info(icons.InfoProps{Class: "size-8"})},
}package empty
import "github.com/alternayte/gx"
var EmptyTitleFixtures = gx.Fixtures[EmptyTitleProps]{"Title": {Children: gx.Text("No projects")}}The theme must define these tokens: --muted, --muted-foreground, --foreground, --primary.
Usage
A placeholder for a view with no data.
<empty.Empty>
<empty.EmptyHeader>
<empty.EmptyMedia variant={empty.Icon}><icons.Info /></empty.EmptyMedia>
<empty.EmptyTitle>No projects</empty.EmptyTitle>
<empty.EmptyDescription>Create your first project to start.</empty.EmptyDescription>
</empty.EmptyHeader>
<empty.EmptyContent>
<button.Button>New project</button.Button>
</empty.EmptyContent>
</empty.Empty>The empty state has no visible border. Add class="border" for a dashed outline.
EmptyMedia with the Icon variant draws a tile behind the icon.
Examples
Empty: Full
<empty.Empty>
<empty.EmptyHeader>
<empty.EmptyMedia variant={empty.Icon}><icons.Info /></empty.EmptyMedia>
<empty.EmptyTitle>No projects</empty.EmptyTitle>
<empty.EmptyDescription>Create your first project to start.</empty.EmptyDescription>
</empty.EmptyHeader>
<empty.EmptyContent><button.Button>New project</button.Button></empty.EmptyContent>
</empty.Empty>Empty: Outline
<empty.Empty class="border">
<empty.EmptyHeader>
<empty.EmptyTitle>No results</empty.EmptyTitle>
<empty.EmptyDescription>Change the filter and search again.</empty.EmptyDescription>
</empty.EmptyHeader>
</empty.Empty>EmptyContent: Empty
<empty.EmptyContent children={gx.Frag()} />EmptyDescription: Text
<empty.EmptyDescription>Create your first project.</empty.EmptyDescription>EmptyHeader: Empty
<empty.EmptyHeader children={gx.Frag()} />EmptyMedia: Icon
<empty.EmptyMedia variant={empty.Icon}><icons.Info /></empty.EmptyMedia>EmptyMedia: Default
<empty.EmptyMedia><icons.Info class="size-8" /></empty.EmptyMedia>EmptyTitle: Title
<empty.EmptyTitle>No projects</empty.EmptyTitle>API reference
A tag sets a prop by its name with a lower-case first letter: Class is class.
empty.Empty
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the content of the empty state. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
empty.EmptyContent
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the content below the header, for example the actions. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
empty.EmptyDescription
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the description text. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
empty.EmptyHeader
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the content of the header: the media, the title and the description. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
empty.EmptyMedia
| Prop | Type | Default | Description |
|---|---|---|---|
Variant |
Variant |
Default |
Variant sets the look of the media: Default or Icon. Icon draws a muted rounded box. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the media, for example an icon. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
empty.EmptyTitle
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the title text. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
Do and do not
Do
- Say what is missing in
EmptyTitle. - Put the action that fixes the state in
EmptyContent.
Don't
- Do not use an empty state for an error. Use an alert.
- Do not put more than two actions in
EmptyContent.
Keyboard
| Key | Action |
|---|---|
| None | The component is static. |