Skip to content

Commit

Permalink
Docs/guides 2.1 tag helpers (#219)
Browse files Browse the repository at this point in the history
* Guides 2.1: Add documentation for TagHelper

* Simplify the part code example

* Extract tag_helper documentation to separate file

This will improve readiness

* Improve header hierarchy for better readability

* Fix the ordering to not clash with existing files

* Apply suggestions from code review

---------

Co-authored-by: Luca Guidi <[email protected]>
  • Loading branch information
swilgosz and jodosha authored Nov 9, 2023
1 parent 0220d32 commit dd0d37a
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 1 deletion.
2 changes: 1 addition & 1 deletion content/v2.1/helpers/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Overview
order: 10
---

Hanami provides a range of standard helpers for you to use in your views.
Hanami provides a range of standard helpers for you to use in your [views](/v2.1/views/overview/).

You can read more about where helpers fit within your views in the [view helpers guide](/v2.1/views/helpers/).

Expand Down
204 changes: 204 additions & 0 deletions content/v2.1/helpers/tag_helper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
title: Tag Helper
order: 30
---

This helper makes accessible all the HTML-related tags.

## Usage

Here is how you can use it **in templates**:

```ruby
<%= tag.div(id: "el") do %>
<p>Template content can be mixed in.</p>
<%= tag.p("Also nested tag builders.") %>
<% end %>
```

This will render:

```html
<div id="el">
<p>Template content can be mixed in.</p>
<p>Also nested tag builders.</p>
</div>
```

[In parts](/v2.1/views/parts), you can access your helpers via the `helpers` object.

Given you have a view exposure defined:

```ruby
# app/views/books/show.rb

module Bookshelf
module Views
module Books
class Show < Bookshelf::View
expose :book do
Book.new(title: "Hanami")
end
end
end
end
end
```

Then you can have the part with the helper used.

```ruby
# app/views/parts/book.rb

module Bookshelf
module Views
module Parts
module Book
def formatted_title
helpers.tag.h1(value.title)
end
end
end
end
end
```

Then in the template you can just access the part:

```ruby
# app/templates/books/show.html.erb

<%= book.formatted_title %>
```
## Features
Here are lists of features with the corresponding examples:
**Auto-closing tags according to HTML5 spec**
```ruby
tag.div # => <div></div>
```

**Content string as first argument**

```ruby
tag.img # => <img>
tag.div("First argument is content") # => <div>First argument is content</div>
```

**Accepts content as block returning a string**

```ruby
tag.div { "Content in the block" } # => <div>Content in the block</div>
```

**Allows for nesting tags via argument or block**

```ruby
tag.div(tag.p("Nested tag builder")) # => <div><p>Nested tag builder</p></div>

tag.div do
tag.p("Also nested tag builders.")
end
```

**It builds attributes from given hash**

```ruby
tag.div("With Additional attributes", class: ["a", "b"]) # => <div class="a b">With additional attributes</div>
```

**Builds nested HTML attributes attributes from given hash**

```ruby
tag.div(id: "el", data: {x: "y"}) # => <div id="el" data-x="y"></div>
tag.div(id: "el", aria: {x: "y"}) # => <div id="el" aria-x="y"></div>
```

**Allows for dynamic attributes visibility control**

```ruby
tag.div("Dynamic attributes", class: {"a": true, "b": false}) # => <div class="a">Dynamic Attributes</div>
```

**Supports custom tags**

```ruby
tag.custom_tag("hello") # => <custom-tag>hello</custom-tag>
```


## Escaping HTML input

The tag contents are automatically escaped for security reasons:

```ruby
tag.p("<script>alert()</script>") # => <p>&lt;script&gt;alert()&lt;/script&gt;</p>
tag.p(class: "<script>alert()</script>") # => <p class="&lt;script&gt;alert()&lt;/script&gt;"></p>
```

To bypass it use `html_safe` on the given content

```ruby
tag.p("<em>safe content</em>".html_safe) # => <p><em>safe content</em></p>
```

## link_to helper

For anchors, we have a dedicated wrapper `link_to` on `tag.a`, that shares all the features with the [tag helpers](/v2.1/helpers/overview#tag-helper).

Returns an anchor tag for the given contents and URL.
### Usage

The difference is, that you may pass `url` as a second argument, right after the content.

```ruby
link_to(content, url, **attributes)

link_to("Home", "/")
# => <a href="/">Home</a>
```

The URL becomes first argument in case the block is passed.

```ruby
link_to("/") { "Home" }
# => <a href="/">Home</a>

link_to("Home", "/", class: "button") %>
# => <a href="/" class="button">Home</a>
```

### Automatic escaping

The tag's contents are automatically escaped (unless marked as HTML safe).

```ruby
link_to("<script>alert('xss')</script>", "/")
# => <a href="/">&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;</a>

link_to("/") { "<script>alert('xss')</script>" }
# => <a href="/">&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;</a>
```

## token_list helper

This helper returns a string of space-separated tokens from a range of given arguments. It's intended for building an HTML tag attribute value, such as a list of class names

### Usage

```ruby
token_list("foo", "bar")
# => "foo bar"
#
token_list("foo", "foo bar")
# => "foo bar"
#
token_list({ foo: true, bar: false })
# => "foo"
#
token_list(nil, false, 123, "", "foo", { bar: true })
# => "123 foo bar"
```

0 comments on commit dd0d37a

Please sign in to comment.