|
1 | 1 | # Attributes deep dive
|
2 | 2 |
|
3 |
| -You’ve just rebuilt 90% of Phlex so you know a thing or two about rendering attributes. |
| 3 | +You’ve just rebuilt 90% of Phlex so you know a thing or two about rendering attributes, right? |
| 4 | + |
| 5 | +In the previous example, we rendered attributes like this: |
| 6 | + |
| 7 | +```ruby |
| 8 | +attributes.each do |key, value| |
| 9 | + @buffer << " #{key}=\"#{value}\"" |
| 10 | +end |
| 11 | +``` |
4 | 12 |
|
5 | 13 | ## Keys
|
6 | 14 |
|
7 |
| -- Difference between string and symbol keys |
| 15 | +If you use symbols for keys, Phlex will replace underscores `_` with dashes `-`. This is because the convention in HTML is to use dashes, while on the Ruby side, dashes are not allowed in symbols. |
| 16 | + |
| 17 | +If you need to keep an underscore in the attribute name, you can use a string instead: |
8 | 18 |
|
9 |
| -## Values |
| 19 | +::: code-group |
10 | 20 |
|
11 |
| -- Strings |
12 |
| -- Arrays |
13 |
| -- Sets |
14 |
| -- Booleans |
15 |
| -- Custom objects |
| 21 | +```ruby [component] |
| 22 | +h1(data_controller: "hello") { "Hello!" } |
| 23 | +h1("data_controller" => "hello") { "Hello!" } |
| 24 | +``` |
| 25 | + |
| 26 | +```html [output] |
| 27 | +<h1 foo-bar="hello">👋 Hello World!</h1> |
| 28 | +<h1 foo_bar="hello">👋 Hello World!</h1> |
| 29 | +``` |
| 30 | + |
| 31 | +::: |
16 | 32 |
|
17 | 33 | ## Nested attributes
|
18 | 34 |
|
19 |
| -- Describe how hashes work |
| 35 | +You can nest attributes by using a hash as the value. The hash will be flattened with a dash between each level: |
| 36 | + |
| 37 | +::: code-group |
| 38 | + |
| 39 | +```ruby [component] |
| 40 | +h1(data: { controller: "hello" }) { "Hello!" } |
| 41 | +``` |
| 42 | + |
| 43 | +```html [output] |
| 44 | +<h1 data-controller="hello">👋 Hello World!</h1> |
| 45 | +``` |
| 46 | + |
| 47 | +::: |
| 48 | + |
| 49 | +## Attribute values |
| 50 | + |
| 51 | +You’ve seen how string values work. Symbols behave the same way. You’ve also seen how to nest attributes with hashes. But Phlex allows a few other types of attribute value. |
| 52 | + |
| 53 | +### Arrays and sets |
| 54 | + |
| 55 | +::: code-group |
| 56 | + |
| 57 | +```ruby [component] |
| 58 | +h1(class: ["foo", "bar"]) { "Hello!" } |
| 59 | +h1(class: Set["foo", "bar"]) { "Hello!" } |
| 60 | +``` |
| 61 | + |
| 62 | +```html [output] |
| 63 | +<h1 class="foo bar">Hello!</h1> |
| 64 | +<h1 class="foo bar">Hello!</h1> |
| 65 | +``` |
| 66 | + |
| 67 | +::: |
| 68 | + |
| 69 | +### Booleans |
| 70 | + |
| 71 | +Booleans are a special case. If the value is `true`, Phlex will render the attribute without a value. If the value is `false`, Phlex will not render the attribute at all. |
| 72 | + |
| 73 | +::: code-group |
| 74 | + |
| 75 | +```ruby [component] |
| 76 | +textarea(disabled: true) |
| 77 | +textarea(disabled: false) |
| 78 | +``` |
| 79 | + |
| 80 | +```html [output] |
| 81 | +<textarea disabled></textarea> <textarea></textarea> |
| 82 | +``` |
| 83 | + |
| 84 | +::: |
| 85 | + |
| 86 | +::: tip |
| 87 | +Some HTML attributes such as `contenteditable` require you to pass `"true"` or `"false"` as a string. These are not technically “boolean” attributes, they're “enumerated” attributes. The distinction is subtle but important. |
| 88 | + |
| 89 | +::: |
20 | 90 |
|
21 | 91 | ## Special attributes
|
22 | 92 |
|
23 |
| -- `style` |
24 |
| -- `class` |
| 93 | +### `class` |
| 94 | + |
| 95 | +The `class` attribute is special. It behaves differently when you pass a Hash as a value, allowing you to conditionally add classes. Here, the class `active` is added because `is_active` is _truthy_, and the class `disabled` is not added because `is_disabled` is _falsy_: |
| 96 | + |
| 97 | +::: code-group |
| 98 | + |
| 99 | +```ruby [component] |
| 100 | +is_active = true |
| 101 | +is_disabled = false |
| 102 | + |
| 103 | +a(class: { active: is_active, disabled: is_disabled }) { "Click me" } |
| 104 | +``` |
| 105 | + |
| 106 | +```html [output] |
| 107 | +<a class="active">👋 Hello World!</a> |
| 108 | +``` |
| 109 | + |
| 110 | +::: |
| 111 | + |
| 112 | +You can also use this with an array: |
| 113 | + |
| 114 | +::: code-group |
| 115 | + |
| 116 | +```ruby{6} [component] |
| 117 | +is_active = true |
| 118 | +is_disabled = false |
| 119 | +
|
| 120 | +a( |
| 121 | + class: [ |
| 122 | + "button", |
| 123 | + "active" => is_active, |
| 124 | + "disabled" => is_disabled |
| 125 | + ] |
| 126 | +) { "Click me" } |
| 127 | +``` |
| 128 | + |
| 129 | +```html [output] |
| 130 | +<a class="button active">👋 Hello World!</a> |
| 131 | +``` |
| 132 | + |
| 133 | +In this example, the `button` class is always added, while the `active` and `disabled` classes are conditional. You can read `=>` as “if”. |
| 134 | + |
| 135 | +### `style` |
| 136 | + |
| 137 | +Like `class`, the `style` attribute has special behaviour. If you pass a Hash to `style`, Phlex will convert it to a CSS string: |
| 138 | + |
| 139 | +::: code-group |
| 140 | + |
| 141 | +```ruby [component] |
| 142 | +h1(style: { color: "red", font_size: "16px" }) { "Hello!" } |
| 143 | +``` |
| 144 | + |
| 145 | +```html [output] |
| 146 | +<h1 style="color: red; font-size: 16px;">Hello!</h1> |
| 147 | +``` |
| 148 | + |
| 149 | +::: |
| 150 | + |
| 151 | +### `href` on an `<a>` tag |
| 152 | + |
| 153 | +It’s worth noting here that Phlex will not allow you to set the `href` attribute to anything that begins with `javascript:`. This is a security feature to prevent cross-site-scripting (XSS) attacks. |
| 154 | + |
| 155 | +## Event attributes |
| 156 | + |
| 157 | +Event attributes such as `onclick` are disallowed to prevent cross-site-scripting (XSS) attacks. |
0 commit comments