{"id":42274189,"url":"https://github.com/stackus/goht","last_synced_at":"2026-01-27T07:38:06.450Z","repository":{"id":215035770,"uuid":"737185060","full_name":"stackus/goht","owner":"stackus","description":"A Haml, Slim, and EGO template engine for Go","archived":false,"fork":false,"pushed_at":"2025-07-24T02:26:45.000Z","size":2986,"stargazers_count":122,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-24T05:49:03.436Z","etag":null,"topics":["golang","haml","html","language-server","language-server-protocol","lsp","slim","templates","type-safe"],"latest_commit_sha":null,"homepage":"https://goht.dev","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stackus.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-12-30T05:24:10.000Z","updated_at":"2025-07-24T02:26:49.000Z","dependencies_parsed_at":"2024-04-12T00:38:56.763Z","dependency_job_id":"70ad4aed-ff1b-4276-8c9a-02108e7b2f1e","html_url":"https://github.com/stackus/goht","commit_stats":null,"previous_names":["stackus/hamlet","stackus/goht"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/stackus/goht","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackus%2Fgoht","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackus%2Fgoht/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackus%2Fgoht/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackus%2Fgoht/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stackus","download_url":"https://codeload.github.com/stackus/goht/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackus%2Fgoht/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28808322,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T07:14:39.408Z","status":"ssl_error","status_checked_at":"2026-01-27T07:14:39.098Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","haml","html","language-server","language-server-protocol","lsp","slim","templates","type-safe"],"created_at":"2026-01-27T07:38:02.591Z","updated_at":"2026-01-27T07:38:06.439Z","avatar_url":"https://github.com/stackus.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# GoHT (Go HTML Templates)\nA [Haml](http://haml.info/), [Slim](https://slim-template.github.io/), and EGO template engine and file generation tool for Go.\n\n![GoHT](docs/goht_header_html.png)\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/stackus/goht)](https://goreportcard.com/report/github.com/stackus/goht)\n[![](https://godoc.org/github.com/stackus/goht?status.svg)](https://pkg.go.dev/github.com/stackus/goht)\n[![Coverage Status](https://coveralls.io/repos/github/stackus/goht/badge.svg?branch=main)](https://coveralls.io/github/stackus/goht?branch=main)\n\n## Table of Contents\n- [Features](#features)\n- [Quick Start](#quick-start)\n- Template Engines\n  - Haml: [Supported Haml Syntax \u0026 Features](#supported-haml-syntax--features)\n    - [Unsupported Haml Features](#unsupported-haml-features)\n  - Slim: [Supported Slim Syntax \u0026 Features](#supported-slim-syntax--features)\n    - [Unsupported Slim Features](#unsupported-slim-features)\n  - EGO: [Supported EGO tags](#supported-ego-tags)\n- [GoHT CLI](#goht-cli)\n- [IDE Support](#ide-support)\n  - [LSP](#lsp)\n- [Library Installation](#library-installation)\n- [Using GoHT](#using-goht)\n  - [Using GoHT with HTTP handlers](#using-goht-with-http-handlers)\n  - [A big nod to Templ](#a-big-nod-to-templ)\n- [The GoHT template](#the-goht-template)\n- [GoHT Syntax](#goht-syntax)\n  - [GoHT template differences](#goht-template-differences)\n    - [Go package and imports](#go-package-and-imports)\n    - [Multiple templates per file](#multiple-templates-per-file)\n    - [Doctypes](#doctypes)\n    - [Inlined code](#inlined-code)\n    - [Rendering code](#rendering-code)\n    - [Attributes](#attributes)\n    - [Classes](#classes)\n    - [Object References](#object-references)\n    - [Inlined Tags](#inlined-tags)\n    - [Filters](#filters)\n    - [Template nesting](#template-nesting)\n    - [Named Slots](#named-slots)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n- Full [Haml](http://haml.info/) language support \n- Full [Slim](https://slim-lang.com/) language support\n- EGO support ([EJS](https://ejs.co/) or [ERB](https://docs.ruby-lang.org/en/2.3.0/ERB.html) like syntax)\n- Templates are compiled to type-safe Go and not parsed at runtime\n- Multiple templates per file\n- Mix Go and templates together in the same file\n- Easy nesting of templates\n\n## Quick Start\nFirst create a GoHT file, a file which mixes Go and Haml (and Slim!) with a `.goht` extension:\n```haml\npackage main\n\nvar siteTitle = \"GoHT\"\n\n@haml SiteLayout(pageTitle string) {\n  !!!\n  %html{lang:\"en\"}\n    %head\n      %title= siteTitle\n    %body\n      %h1= pageTitle\n      %p A type-safe HAML template engine for Go.\n      = @children\n}\n\n@slim HomePage() {\n  = @render SiteLayout(\"Home Page\")\n    p This is the home page for GoHT.\n}\n\n@ego ListItemFragment(item Item) {\n  \u003cli\u003e\n    \u003ca href=\"\u003c%= item.URL %\u003e\"\u003e\n      \u003c%= item.Name %\u003e\n    \u003c/a\u003e\n  \u003c/li\u003e\n}\n```\n\nYour next step will be to process the GoHT file to parse the GoHT code and generate the Go code using the GoHT [CLI](#goht-cli) tool:\n```sh\ngoht generate\n```\n\nUse the generated Go code to render HTML in your application:\n```go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"net/http\"\n)\n\nfunc main() {\n  http.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n    _ = HomePage().Render(r.Context(), w)\n  })\n\n  fmt.Println(\"Server starting on port 8080...\")\n  if err := http.ListenAndServe(\":8080\", nil); err != nil {\n    log.Fatal(err)\n  }\n}\n```\nWhich would serve the following HTML:\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eGoHT\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003ch1\u003eHome Page\u003c/h1\u003e\n    \u003cp\u003eA type-safe Haml template engine for Go.\u003c/p\u003e\n    \u003cp\u003eThis is the home page for GoHT.\u003c/p\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Supported Haml Syntax \u0026 Features\n- [x] Doctypes (`!!!`)\n- [x] Tags (`%tag`)\n- [x] Attributes (`{name: value}`) [(more info)](#attributes)\n- [x] Classes and IDs (`.class`, `#id`) [(more info)](#classes)\n- [x] Object References (`[obj]`) [(more info)](#object-references)\n- [x] Unescaped Text (`!` `!=`)\n- [x] Comments (`/` `-#`)\n- [x] Self-closing Tags (`%tag/`)]\n- [x] Inline Interpolation (`#{value}`)\n- [x] Inlining Code (`- code`)\n- [x] Rendering Code (`= code`)\n- [x] Filters (`:plain`, ...) [(more info)](#filters)\n- [x] Long Statement wrapping (`\\`), (`,`)\n- [x] Whitespace Removal (`%tag\u003e`, `%tag\u003c`) [(more info)](#whitespace-removal)\n\n### Unsupported Haml Features\n- [ ] Probably something I've missed, please raise an issue if you find something missing.\n\n## Supported Slim Syntax \u0026 Features\n- [x] Doctypes (`doctype`)\n- [x] Tags (`tag`)\n- [x] Attributes (`{name: value}`) [(more info)](#attributes)\n- [x] Classes and IDs (`.class`, `#id`) [(more info)](#classes)\n- [x] Inline Tags (`tag: othertag`)\n- [x] Unescaped Text (`|`)\n- [x] Comments (`/`, `/!`)\n- [x] Self-closing Tags (`tag/`)\n- [x] Inline Interpolation (`#{value}`)\n- [x] Inlining Code (`- code`)\n- [x] Rendering Code (`= code`, `== code`)\n- [x] Filters (`:javascript`, `:css`) [(more info)](#filters)\n- [x] Long Statement wrapping (`\\`), (`,`)\n- [x] Whitespace Addition (`tag\u003c` `tag\u003e`) [(more info)](#whitespace-addition)\n\n### Unsupported Slim Features\n\n- [ ] Probably something I've missed, please raise an issue if you find something missing.\n\n### Supported EGO tags\n\nThe basic EGO syntax is to start tags and with `\u003c%` and end with `%\u003e`.\n\nThe opening tags that are supported are:\n- `\u003c%` - Start of a Go code block\n  - Examples: `\u003c% for k, v := range list { %\u003e`, `\u003c% foo := \"bar\" %\u003e`, `\u003c% if foo == \"bar\" { %\u003e`\n- `\u003c%-` - Start of a Go code block with whitespace stripping\n  - Examples: `\u003c%- for k, v := range list { %\u003e`, `\u003c%- foo := \"bar\" %\u003e`, `\u003c%- if foo == \"bar\" { %\u003e`\n- `\u003c%=` - Start of a Go output block; supports the formatting directives like `%d`, `%v`, etc.\n  - Examples: `\u003c%= unsafeHTML %\u003e`, `\u003c%= %t someBool %\u003e`, `\u003c%= props.Value %\u003e`\n- `\u003c%!` - Start of a Go unescaped output block; supports the formatting directives like `%d`, `%v`, etc.\n  - Examples: `\u003c%! safeHTML %\u003e`, `\u003c%! %t someBool %\u003e`, `\u003c%! props.Value %\u003e`\n- `\u003c%@` - Start of a command block; Either `@render` or `@children`\n  - Examples: `\u003c%@ render ExampleChild(props ChildProps) { %\u003e`, `\u003c%@ children %\u003e`\n- `\u003c%#` - Start of a comment; the content will be ignored\n  - Examples: `\u003c%# This is a comment %\u003e`\n\nThe closing tags that are supported are:\n- `%\u003e` - Normal closing tag\n  - Examples: `\u003c% foo := \"bar\" %\u003e`, `\u003c%= foo %\u003e`\n- `-%\u003e` - Closing tag with whitespace stripping\n  - Examples: `\u003c% foo := \"bar\" -%\u003e`, `\u003c%= foo -%\u003e`\n- `$%\u003e` - Closing tag with newline stripping (one newline)\n  - Examples: `\u003c% foo := \"bar\" $%\u003e`, `\u003c%= foo $%\u003e`\n\n## GoHT CLI\n\n### Installation\n```sh\ngo install github.com/stackus/goht/cmd/goht@latest\n```\n\n### Usage\nUse `generate` to generate Go code from GoHT template files,\nthat are new or newer than the generated Go files, in the current directory and subdirectories:\n```sh\ngoht generate\n```\nUse the `--path` flag to specify a path to generate code for:\n```sh\ngoht generate --path=./templates\n```\nIn both examples, the generated code will be placed in the same directory as the template files.\n\nUse the `--force` to generate code for all GoHT template files, even if they are older than the generated Go files:\n```sh\ngoht generate --force\n```\nSee more options with `goht help generate` or `goht generate -h`.\n\n## IDE Support\n\n\u003e Note: The IDE extensions are being worked on to add the new Slim syntax highlighting.\n\n![vscode_ide_example.png](docs/vscode_ide_example.png)\n- VSCode [Extension](https://marketplace.visualstudio.com/items?itemName=stackus.goht-vscode) and code [repository](https://github.com/stackus/goht-vscode)\n- JetBrains (GoLand and others) [Plugin](https://plugins.jetbrains.com/plugin/23783-goht) and code [repository](https://github.com/stackus/goht-jetbrains)\n- [TextMate Bundle](bundle)\n  - Offers only basic syntax highlighting and is a work in progress.\n\n### LSP\nThe GoHT CLI has been updated to include an LSP server.\nSee `goht help lsp` for more information.\nThis will enable development of extensions and plugins for GoHT in various editors and IDEs.\n\nContributions are welcome. Please see the [contributing guide](CONTRIBUTING.md) for more information.\n\n\n## Library Installation\nWhen you are using GoHT you will typically be dealing with the generated Go code, and not the GoHT runtime directly.\nHowever, if you need to install the GoHT library, you can do so with:\n```sh\ngo get github.com/stackus/goht\n```\n\n## Using GoHT\nTo start using GoHT, the first step is to create a GoHT file with one or more Haml templates.\nIf you need guidance, the section [The GoHT template](#the-goht-template) has all the information you need.\n\nWith your GoHT files written, the next step involves generating Go code from them.\nThe [CLI](#goht-cli) tool handles this generation step.\nIt's a straightforward process that converts your GoHT files and templates into ready to run Go files.\n\nEach generated Go file will include a function corresponding to each of your templates.\nThe names of the functions are not altered at all,\nif you want them to be exported in Go then you need to use an uppercase letter for the first character of the template name.\n\nWhen this function is executed, it yields a `*goht.Template`.\nThis is what you'll use to render your templates in the application.\n\n```go\npackage main\n\nimport (\n  \"context\"\n  \"os\"\n\n  \"github.com/stackus/goht/examples/tags\"\n)\n\nfunc main() {\n  tmpl := tags.RemoveWhitespace()\n\n  err := tmpl.Render(context.Background(), os.Stdout)\n  if err != nil {\n    panic(err)\n  }\n}\n```\nThe above would render the `RemoveWhitespace` example from the [examples](/examples) directory in this repository,\nand would output the following:\n```html\n\u003cp\u003eThis text has no whitespace between it and the parent tag.\u003c/p\u003e\n\u003cp\u003e\nThere is whitespace between this text and the parent tag.\u003cp\u003eThis text has no whitespace between it and the parent tag.\nThere is also no whitespace between this tag and the sibling text above it.\nFinally, the tag has no whitespace between it and the outer tag.\u003c/p\u003e\u003c/p\u003e\n```\nThe second parameter passed into the `Render` method can be anything that implements the `io.Writer` interface,\nsuch as a file or a buffer, or the `http.ResponseWriter` that you get from an HTTP handler.\n\n### Using GoHT with HTTP handlers\nUsing the GoHT templates is made straightforward.\n```go\npackage main\n\nimport (\n  \"fmt\"\n  \"log\"\n  \"net/http\"\n\n  \"github.com/stackus/goht/examples/hello\"\n)\n\nfunc main() {\n  http.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n    _ = hello.World().Render(r.Context(), w)\n  })\n\n  fmt.Println(\"Server starting on port 8080...\")\n  if err := http.ListenAndServe(\":8080\", nil); err != nil {\n    log.Fatal(err)\n  }\n}\n```\n\n**More Examples!**\n\nThere are a number of examples showing various template features in the [examples](examples) directory.\n\n### A big nod to Templ\nThe way that you use GoHT is very similar to how you would use [Templ](https://templ.guide). This is no accident as I am a big fan of the work being done with that engine.\n\nAfter getting the Haml properly lexed and parsed, I did not want to reinvent the wheel and come up with a whole new rendering API.\nThe API that Templ presents is nice and easy to use, so I decided to replicate it in GoHT.\n\n## The GoHT template\nGoHT templates are files with the extension `.goht` that when processed will produce a matching Go file with the extension `.goht.go`.\n\nIn these files you are free to write any Go code that you wish, and then drop into Haml mode using the `@haml` directive.\n\n\u003e Note: The original `@goht` directive is still supported for HAML templating, but it is deprecated and will be removed in a future version.\n\nThe following starts the creation of a SiteLayout template:\n```haml\n@haml SiteLayout() {\n\nor\n\n@slim SiteLayout() {\n\nor\n\n@ego SiteLayout() {\n```\n\nGoHT templates are closed like Go functions, with a closing brace `}`. So a complete but empty example is this:\n```haml\n@haml SiteLayout() {\n}\n\nor\n\n@slim SiteLayout() {\n}\n\nor\n\n@ego SiteLayout() {\n}\n```\nInside the templates you must indent the contents of the template code at least once. This is a requirement of GoHT.\n\n## GoHT Syntax\nThe Haml syntax is documented at the [Haml](http://haml.info/) website.\nPlease see that site or the [Haml Reference](https://haml.info/docs/yardoc/file.REFERENCE.html) for more information.\nThe Slim syntax is documented at the [Slim](https://slim-lang.com/) website.\n\nGoHT has implemented nearly all Haml and Slim syntax that are whitespace indented syntaxes. It also supports the EGO syntax which is a syntax more like normal HTML.\nSo, if you are already familiar with Haml, Slim, or are familiar with either EJS (Embedded JavaScript) or ERB (Embedded Ruby) then you should be able to jump right in.\nThere are some minor differences that I will document in the next section.\n\n### GoHT template differences\n\nImportant differences are:\n- [Go package and imports](#go-package-and-imports): You can declare a package and imports for your templates.\n- [Multiple templates per file](#multiple-templates-per-file): You can declare as many templates in a file as you wish.\n- [Doctypes](#doctypes): Haml and Slim only. Limited doctype support.\n- [Indents](#indents): GoHT follows the rules of GoFMT for indents.\n- [Inlined code](#inlined-code): You won't be using Ruby here, you'll be using Go.\n- [Rendering code](#rendering-code): The catch is what is being outputted will need to be a string in all cases.\n- [Attributes](#attributes): Haml and Slim only. Only the Ruby 1.9 (`{...}`) style of attributes is supported.\n- [Classes](#classes): Haml and Slim only. Multiple sources of classes are supported.\n- [Object References](#object-references): Haml Only: Limited support for object references.\n- [Filters](#filters): Haml and Slim only. Partial list of supported filters.\n- [Template nesting](#template-nesting): Templates can be nested, and content can be passed into them.\n\nIn the above list, EGO doesn't have many of the limitations of the other two languages.\nThis is because anything outside the EGO tags can be or contain whatever you want.\n\n### Go package and imports\nYou can provide a package name at the top of your GoHT template file. If you do not provide one then `main` will be used.\n\nYou may also import any packages that you need to use in your template. The imports you use and the ones brought in by GoHT will be combined and deduplicated.\n\n### Multiple templates per file\nYou can declare as many templates in a file as you wish.\nEach template must have a unique name in the module they will be output into.\nYou may also mix all three template types in the same file.\n```haml\n@slim SiteLayout() {\n}\n\n@haml HomePage() {\n}\n\n@ego ListItem(item Item) {\n}\n```\n\nThe templates are converted into Go functions, so they must be valid Go function names.\nThis also means that you can declare them with parameters and can use those parameters in the template.\n```haml\n@haml SiteLayout(title string) {\n  !!!\n  %html{lang:\"en\"}\n    %head\n      %title= title\n    %body\n      -# ... the rest of the template\n}\n```\nThe same applies to Slim templates:\n```slim\n@slim SiteLayout(title string) {\n  doctype html\n  html(lang=\"en\")\n    head\n      title= title\n    body\n      / ... the rest of the template\n}\n```\nAnd to the EGO templates:\n```html\n@ego SiteLayout(title string) {\n  \u003chtml lang=\"en\"\u003e\n    \u003chead\u003e\n      \u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n      \u003c!-- ... the rest of the template --\u003e\n    \u003c/body\u003e\n  \u003c/html\u003e\n}\n```\n\n### Doctypes\nOnly the HTML 5 doctype is supported in the Haml and Slim templates, and is written using `!!!` or `doctype`.\n```haml\n@haml SiteLayout() {\n  !!!\n}\n\n@slim SiteLayout() {\n  doctype\n}\n```\n\n### Indents\nGoHT follows the rules of GoFMT for indents, meaning that you should use tabs for indentation.\nFor the Haml and Slim templates, you must use tabs throughout the entire template.\nFor the EGO templates, you may use spaces after the initial tab indent required for each line.\n\n\u003e Note: Two spaces are being used in this README for display only. Keep that in mind if you copy and paste the examples from this document.\n\nYou must also indent the content of the Haml and Slim templates,\nand the closing brace should be at the same level as the template directive.\n```haml\n@haml SiteLayout() {\n  %html\n    %head\n      %title GoHT\n    %body\n      %h1 GoHT\n}\n```\n\nSlim:\n```slim\n@slim SiteLayout() {\n  doctype\n  html\n    head\n      title GoHT\n    body\n      h1 GoHT\n}\n```\n\nEGO:\n```html\n@ego SiteLayout() {\n  \u003chtml\u003e\n    \u003chead\u003e\n      \u003ctitle\u003eGoHT\u003c/title\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n      \u003ch1\u003eGoHT\u003c/h1\u003e\n    \u003c/body\u003e\n  \u003c/html\u003e\n}\n```\n\n### Inlined code\nYou won't be using Ruby here, you'll be using Go.\n\nIn most situations where we would need to include opening and closing braces in Go, we can omit them in GoHT.\nThis makes it a lot closer to the Ruby-based Haml, and makes the templates easier to read.\nGo will still require that we have a full statement, no shorthands for boolean conditionals.\nSo instead of this with Ruby:\n```haml\n  - if user\n    %strong The user exists\n```\nYou would write this with Go (Go needs the `!= nil` check):\n```haml\n  - if user != nil\n    %strong The user exists\n```\nThere is minimal processing performed on the Go code you put into the templates, so it needs to be valid Go code sans braces.\n\n\u003e You may continue to use the braces in the Haml and Slim templates at the ends of your lines if you wish. Existing code with braces will continue to work without modifications.\n\nLong statements can be split across multiple lines by ending each line with either a backslash `\\` or a comma `,`.\nThe backslashes will be **stripped**, but the commas will be **kept**.\n\n```haml\n  - if user != nil \u0026\u0026 user.Name != \"\"\\\n    \u0026\u0026 user.Age \u003e 0\n    %strong The user is not empty\n```\n\nYou can also spread statements across multiple lines in the EGO templates.\nTake care that the code is valid Go code because the entire statement, with newlines and whitespace, is all captured.\n\n```html\n@ego SiteLayout() {\n  \u003c% if user != nil \u0026\u0026 \n    user.Name != \"\" { %\u003e\n    \u003cstrong\u003eThe user is not empty\u003c/strong\u003e\n  \u003c% } %\u003e\n}\n```\n\n### Rendering code\nLike in Haml, you can output variables and the results of expressions. The `=` script syntax and text interpolation `#{}` are supported for both template languages.\n```haml\n  %strong= user.Name\n  %strong The user's name is #{user.Name}\n```\nSlim:\n```slim\n  strong= user.Name\n  strong The user's name is #{user.Name}\n```\n\nThe catch is what is being outputted will need to be a string in all cases.\nSo instead of writing this to output an integer value:\n```haml\n  %strong= user.Age\n```\nYou would need to write this:\n```haml\n  %strong= fmt.Sprintf(\"%d\", user.Age)\n```\nWhich, to be honest, can be a bit long to write, so a shortcut is provided:\n```haml\n  %strong=%d user.Age\n```\nThe interpolation syntax also supports the shortcut:\n```haml\n  %strong #{user.Name} is #{%d user.Age} years old.\n```\nWhen formatting a value into a string `fmt.Sprintf` is used under the hood, so you can use any of the formatting options that it supports.\n\n### Attributes\n**Haml and Slim Only**\n\n**Only the Ruby 1.9 style of attributes is supported.**\n\nThis syntax is closest to the Go syntax, and is the most readable.\nBetween the attribute name, operator, and value you can include or leave out as much whitespace as you like.\n```haml\n  %a{href: \"https://github.com/stackus/goht\", target: \"_blank\"} GoHT\n```\nYou can supply a value to an attribute using the text interpolation syntax.\n```haml\n  %a{href:#{url}} GoHT\n```\nAttributes can be written over multiple lines, and the closing brace can be on a new line.\n```haml\n  %a{\n    href: \"...\",\n    target: \"_blank\",\n  } GoHT\n```\nAttributes which you want to render conditionally use the `?` operator instead of the `:` operator.\nFor conditional attributes the attribute value is required to be an interpolated value which will be used as the condition in a Go `if` statement.\n```haml\n  %button{\n    disabled ? #{disabled},\n  } Click me\n```\n\u003e Note: The final comma is not required on the last attribute when they are spread across multiple lines like it would be in Go. Including it is fine and will not cause any issues.\n\nCertain characters in the attribute name will require that the name be escaped.\n```haml\n  %button{\n    \"@click\": \"onClick\",\n    \":disabled\": \"disabled\",\n  } Click me\n```\nKeep in mind that attribute names cannot be replaced with an interpolated string; only the value can.\n\nTo support dynamic lists of attributes, you can use the `@attributes` directive.\nThis directive takes a list of arguments which comes in two forms:\n- `map[string]string`\n  - The key is the attribute name, the value is the attribute value.\n  - The attribute will be rendered if the value is not empty.\n- `map[string]bool`\n  - The key is the attribute name, the value is the condition to render the attribute.\n```haml\n  %button{\n    \"@click\": \"onClick\",\n    \":disabled\": \"disabled\",\n    @attributes: #{myAttrs},\n  } Click me\n```\n### Classes\n**Haml and Slim Only**\n\nGoHT supports the `.` operator for classes and also will accept the `class` attribute such as `class:\"foo bar\"`.\nHowever, if the class attribute is given an interpolated value, it will need to be a comma separated list of values.\nThese values can be the following types:\n- `string`\n  - `myClass` variable or `\"foo bar\"` string literal\n- `[]string`\n  - Each item will be added to the class list if it is not blank.\n- `map[string]bool`\n  - The key is the class name, the value is the condition to include the class.\n\nExamples:\n```haml\n  %button.foo.bar.baz Click me\n  %button.fizz{class:\"foo bar baz\"} Click me\n  %button.foo{class:#{myStrClasses, myBoolClasses}} Click me\n```\nAll sources of classes will be combined and deduplicated into a single class attribute.\n\n### Object References\n**Haml Only**\n\nHaml supports using a Ruby object to supply the id and class for a tag using the `[]` object reference syntax.\n\nThis is supported but is rather limited in GoHT.\nThe type that you use within the brackets will be expected to implement at least one or both of the following interfaces:\n```go\ntype ObjectIDer interface {\n  ObjectID() string\n}\n\ntype ObjectClasser interface {\n  ObjectClass() string\n}\n```\nThe result of these methods will be used\nto populate the id and class attributes in a similar way to how Haml would apply the Ruby object references.\n\n### Inlined Tags\n**Slim Only**\n\nGoHT supports inlining tags to keep templates as compact as possible.\n\n```slim\n  ul\n    li: a.First Fist Item\n    li: a.Second Second Item\n    li: a.Third Third Item\n```\n\n### Filters\nOnly the following Haml filters are supported:\n- `:plain` (Haml Only)\n- `:escaped` (Haml Only)\n- `:preserve` (Haml Only)\n- `:javascript`\n- `:css`\n\n### Whitespace Removal\n**Haml Only**\n\nGoHT supports the removal of whitespace between tags. This is done by adding a `\u003e` or `\u003c` to the end of the tag.\n\n- `\u003e` will remove all whitespace between the tag and its parent or siblings.\n- `\u003c` will remove all whitespace between the tag and its first and last child.\n\nBoth can be used together to remove whitespace both inside and outside a tag; the order they're in does not matter.\n\n### Whitespace Addition\n**Slim Only**\n\nGoHT supports the addition of whitespace between tags. This is done by adding a `\u003c` or `\u003e` to the end of the tag.\n\n- `\u003c` will add whitespace before the tag\n- `\u003e` will add whitespace after the tag\n\n### Template nesting\nThe biggest departure from Haml and Slim is how templates can be combined.\nWhen working Haml you could use `= render :partial_name` or `= haml :partial_name` to render a partial.\n\n\nThe `render` and `haml` functions are not available in GoHT, instead you can use the `@render` directive.\n\n**Haml:**\n```haml\n@haml HomePage() {\n  = @render SiteLayout()\n}\n```\n**Slim:**\n```slim\n@slim HomePage() {\n  = @render SiteLayout()\n}\n```\n**EGO:**\n```html\n@ego HomePage() {\n  \u003c%@render SiteLayout() %\u003e\n}\n```\n\nThe above examples would render the `SiteLayout` template, and you would call it with any parameters that it needs.\nYou can also call it and provide it with a block of content to render where the rendered template chooses.\n\n***Haml:**\n```haml\n@haml HomePage() {\n  = @render SiteLayout()\n    %p This is the home page for GoHT.\n}\n```\n**Slim:**\n```slim\n@slim HomePage() {\n  = @render SiteLayout()\n    p This is the home page for GoHT.\n}\n```\n**EGO:**\n```html\n@ego HomePage() {\n  \u003c%@render SiteLayout() { %\u003e\n    \u003cp\u003eThis is the home page for GoHT.\u003c/p\u003e\n  \u003c% } %\u003e\n}\n```\n\nAny content nested under the `@render` directive will be passed into the template that it can render where it wants using the `@children` directive.\n```haml\n@haml SiteLayout() {\n  !!!\n  %html{lang:\"en\"}\n    %head\n      %title GoHT\n    %body\n      %h1 GoHT\n      %p A HAML-like template engine for Go.\n      = @children\n}\n```\n\n### Named Slots\n\nNamed slots are a feature that allows you to define places in your templates that you want to populate with any template content.\nThis allows you to create more complex templates that can be reused in different contexts.\n\n**Haml:**\n```haml\n@haml HamlSlots() {\n  .basic\n    =@slot basic\n  .with-default-content\n    =@slot defaults\n      %span Displayed when nothing is passed in for \"defaults\"\n}\n```\n\n**Slim:**\n```slim\n@slim SlimSlots() {\n  .basic\n    =@slot basic\n  .with-default-content\n    =@slot defaults\n      span Displayed when nothing is passed in for \"defaults\"\n}\n```\n\n**EGO:**\n```html\n@ego EgoSlots() {\n  \u003cdiv\u003e\n    \u003c%@slot basic %\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    \u003c%@slot defaults { %\u003e\n      \u003cspan\u003eDisplayed when nothing is passed in for \"defaults\"\u003c/span\u003e\n    \u003c% } %\u003e\n  \u003c/div\u003e\n}\n```\n\nIn the above examples, the slot for \"basic\" will only be rendered if content is passed in for it.\nThe slot for \"defaults\" will fall back to the default content if no content is passed in for it.\n\n#### Using slots in your program\nMaking use of slots in your program is a simple process:\n\n```go\nerr := SomeTemplate().Render(ctx, w, \n  OtherTemplate().Slot(\"basic\"),\n)\n```\n\nStart by passing in one or more templates into the optional third parameter of the `Render` method.\nThen instead of calling `Render` on the slotted template, call `Slot` with the name of the slot you want it to fill.\n\nThe slotted templates can be any template, and any template can be used as slotted content, including templates that have their own slots.\n\n```go\nerr := Layout().Render(ctx, w,\n  Sidebar().Slot(\"sidebar\"),\n  Header(headerProps).Slot(\"header\"),\n  UserDetailsPage(userProps).Slot(\"main\",\n    LastActionResults(resultsProps).Slot(\"notifications\"),\n  ),\n  Footer().Slot(\"footer\"),\n)\n```\n\nTemplates can use slots, `@slot \u003cname\u003e` and the internally rendered templates, `@render SomeTemplate()`\nand `@children`, to create templates with incredible levels of reuse and composition.\n\n## Contributing\nContributions are welcome. Please see the [contributing guide](CONTRIBUTING.md) for more information.\n\n## License\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackus%2Fgoht","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackus%2Fgoht","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackus%2Fgoht/lists"}