Skip to content

Commit

Permalink
add void closer tags to allow either > or />
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartaccent committed Jan 20, 2025
1 parent e1d1974 commit 4bacac4
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 40 deletions.
48 changes: 22 additions & 26 deletions element.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"github.com/a-h/templ"
"io"
"slices"
)

type (
Expand All @@ -30,21 +29,21 @@ const (
)

var (
// VoidElements is a list of HTML void elements, these are all self-closing.
VoidElements = []string{
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"link",
"meta",
"source",
"track",
"wbr",
// VoidElements is a list of HTML void elements, these dont have children or content.
VoidElements = map[string]string{
"area": ">",
"base": ">",
"br": ">",
"col": ">",
"embed": ">",
"hr": ">",
"img": ">",
"input": ">",
"link": ">",
"meta": ">",
"source": ">",
"track": ">",
"wbr": ">",
}
// NA is an empty set of attributes.
NA = Attrs{}
Expand Down Expand Up @@ -359,7 +358,11 @@ func (e *Element) AddChildren(children ...templ.Component) {

// Render renders the Element to the writer.
func (e *Element) Render(ctx context.Context, w io.Writer) error {
isVoid := slices.Contains(VoidElements, e.Tag)
closer := ">"
voidCloser, isVoid := VoidElements[e.Tag]
if isVoid {
closer = voidCloser
}

if e.Tag != "" {
if _, err := io.WriteString(w, "<"+e.Tag); err != nil {
Expand All @@ -370,15 +373,8 @@ func (e *Element) Render(ctx context.Context, w io.Writer) error {
return err
}
}

if isVoid {
if _, err := io.WriteString(w, " />"); err != nil {
return err
}
} else {
if _, err := io.WriteString(w, ">"); err != nil {
return err
}
if _, err := io.WriteString(w, closer); err != nil {
return err
}
}

Expand Down
29 changes: 15 additions & 14 deletions element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,25 @@ func TestElementTags(t *testing.T) {

// Test rendering a void Element's.
func TestRenderVoidElements(t *testing.T) {
attr := Attrs{"foo": "bar"}
tests := []struct {
name string
nodeFunc func() *Element
expected string
}{
{"area", func() *Element { return &Element{Tag: "area"} }, "<area />"},
{"base", func() *Element { return &Element{Tag: "base"} }, "<base />"},
{"br", func() *Element { return &Element{Tag: "br"} }, "<br />"},
{"col", func() *Element { return &Element{Tag: "col"} }, "<col />"},
{"embed", func() *Element { return &Element{Tag: "embed"} }, "<embed />"},
{"hr", func() *Element { return &Element{Tag: "hr"} }, "<hr />"},
{"img", func() *Element { return &Element{Tag: "img"} }, "<img />"},
{"input", func() *Element { return &Element{Tag: "input"} }, "<input />"},
{"link", func() *Element { return &Element{Tag: "link"} }, "<link />"},
{"meta", func() *Element { return &Element{Tag: "meta"} }, "<meta />"},
{"source", func() *Element { return &Element{Tag: "source"} }, "<source />"},
{"track", func() *Element { return &Element{Tag: "track"} }, "<track />"},
{"wbr", func() *Element { return &Element{Tag: "wbr"} }, "<wbr />"},
{"area", func() *Element { return &Element{Tag: "area", Attrs: attr} }, `<area foo="bar">`},
{"base", func() *Element { return &Element{Tag: "base", Attrs: attr} }, `<base foo="bar">`},
{"br", func() *Element { return &Element{Tag: "br"} }, `<br>`},
{"col", func() *Element { return &Element{Tag: "col", Attrs: attr} }, `<col foo="bar">`},
{"embed", func() *Element { return &Element{Tag: "embed", Attrs: attr} }, `<embed foo="bar">`},
{"hr", func() *Element { return &Element{Tag: "hr"} }, `<hr>`},
{"img", func() *Element { return &Element{Tag: "img", Attrs: attr} }, `<img foo="bar">`},
{"input", func() *Element { return &Element{Tag: "input", Attrs: attr} }, `<input foo="bar">`},
{"link", func() *Element { return &Element{Tag: "link", Attrs: attr} }, `<link foo="bar">`},
{"meta", func() *Element { return &Element{Tag: "meta", Attrs: attr} }, `<meta foo="bar">`},
{"source", func() *Element { return &Element{Tag: "source", Attrs: attr} }, `<source foo="bar">`},
{"track", func() *Element { return &Element{Tag: "track", Attrs: attr} }, `<track foo="bar">`},
{"wbr", func() *Element { return &Element{Tag: "wbr", Attrs: attr} }, `<wbr foo="bar">`},
}

for _, tt := range tests {
Expand Down Expand Up @@ -142,7 +143,7 @@ func TestRenderBasicElement(t *testing.T) {
// Test rendering an image tag with attributes.
func TestRenderImgElement(t *testing.T) {
node := Img(Attrs{"src": "image.png", "alt": "Test Image"})
expected := `<img alt="Test Image" src="image.png" />`
expected := `<img alt="Test Image" src="image.png">`

output := renderElement(t, node)
if output != expected {
Expand Down

0 comments on commit 4bacac4

Please sign in to comment.