Skip to content

Commit 36d3235

Browse files
authored
Merge pull request #11 from hydrostack/hydro-tag-helpers
Add hydro tag helpers
2 parents 9b65274 + 38265bc commit 36d3235

File tree

6 files changed

+432
-6
lines changed

6 files changed

+432
-6
lines changed

docs/content/.vitepress/config.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,18 @@ export default defineConfig({
3939
]
4040
},
4141
{
42-
text: 'Advanced concepts',
42+
text: 'Advanced',
4343
items: [
4444
{ text: 'Request queuing', link: '/advanced/request-queuing' },
4545
{ text: 'Load balancing', link: '/advanced/load-balancing' },
4646
]
4747
},
48+
{
49+
text: 'Utilities',
50+
items: [
51+
{ text: 'View tag helpers', link: '/utilities/view-tag-helpers' },
52+
]
53+
},
4854
{
4955
text: 'Examples',
5056
items: [
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
---
2+
outline: deep
3+
---
4+
5+
# View tag helpers
6+
7+
View tag helpers are an extension built in into Hydro that let you create new kind of view components (called view tag helpers) that can replace partials, editors and regular view components.
8+
9+
Here is a basic example of a view tag helper called `Submit`:
10+
11+
```c#
12+
// Submit.cshtml.cs
13+
14+
public class SubmitTagHelper : HydroTagHelper;
15+
```
16+
17+
```razor
18+
<!-- Submit.cshtml -->
19+
20+
@model SubmitTagHelper
21+
22+
<button class="btn btn-primary" type="submit">
23+
Save
24+
</button>
25+
```
26+
27+
Now we can use our tag helper in any other razor view:
28+
29+
```razor
30+
<!-- SomeForm.cshtml -->
31+
32+
<submit />
33+
```
34+
35+
## Parameters
36+
37+
View tag helpers use parameters to pass the data from a caller to the view. Example:
38+
39+
```c#
40+
// Alert.cshtml.cs
41+
42+
public class AlertTagHelper : HydroTagHelper
43+
{
44+
public string Message { get; set; }
45+
}
46+
```
47+
48+
```razor
49+
<!-- Alert.cshtml -->
50+
51+
@model AlertTagHelper
52+
53+
<div class="alert">
54+
@Model.Message
55+
</div>
56+
```
57+
58+
Now we can set a value on the `message` attribute that will be passed to our `AlertTagHelper`:
59+
60+
```razor
61+
<!-- Index.cshtml -->
62+
63+
<alert message="Success" />
64+
```
65+
66+
Parameter names are converted to kebab-case when used as attributes on tags, so:
67+
- `Message` property becomes `message` attribute.
68+
- `StatusCode` property becomes `status-code` attribute.
69+
70+
## Dynamic attributes
71+
72+
All attributes passed to the view tag helper by the caller are available in a view definition, even when they are not defined as properties.
73+
We can use this feature to pass optional html attributes to the view, for example:
74+
75+
```c#
76+
// Alert.cshtml.cs
77+
78+
public class AlertTagHelper : HydroTagHelper
79+
{
80+
public string Message { get; set; }
81+
}
82+
```
83+
84+
```razor
85+
<!-- Alert.cshtml -->
86+
87+
@model AlertTagHelper
88+
89+
<div class="alert @Model.Attribute("class")">
90+
@Model.Message
91+
</div>
92+
```
93+
94+
Now we can set an optional attribute `class` that will be added to the final view:
95+
96+
```razor
97+
<!-- Index.cshtml -->
98+
99+
<alert message="Success" class="alert-green" />
100+
```
101+
102+
## Child content
103+
104+
View tag helpers support passing the child html content, so it can be used later when rendering the tag. Example:
105+
106+
```c#
107+
// DisplayField.cshtml.cs
108+
109+
public class DisplayFieldTagHelper : HydroTagHelper
110+
{
111+
public string Title { get; set; };
112+
}
113+
```
114+
115+
```razor
116+
<!-- DisplayField.cshtml -->
117+
118+
@model DisplayFieldTagHelper
119+
120+
<div class="display-field">
121+
<div class="display-field-title">
122+
@Model.Title
123+
</div>
124+
125+
<div class="display-field-content">
126+
@Model.Slot()
127+
</div>
128+
</div>
129+
```
130+
131+
Usage:
132+
133+
```razor
134+
<!-- SomePage.cshtml -->
135+
136+
<display-field title="Price">
137+
<i>199</i> EUR
138+
</display-field>
139+
```
140+
141+
Remarks:
142+
- `Model.Slot()` renders the child content passed by the tag caller
143+
144+
145+
## Slots
146+
147+
Slots are placeholders for html content inside view tag helpers that can be passed by the caller. Here is an example of a `Card` tag:
148+
149+
```c#
150+
// Card.cshtml.cs
151+
152+
public class CardTagHelper : HydroTagHelper;
153+
```
154+
155+
```razor
156+
<!-- Card.cshtml -->
157+
158+
@model CardTagHelper
159+
160+
<div class="card">
161+
<div class="card-header">
162+
@Model.Slot("header")
163+
</div>
164+
165+
<div class="card-content">
166+
@Model.Slot()
167+
</div>
168+
169+
<div class="card-footer">
170+
@Model.Slot("footer")
171+
</div>
172+
</div>
173+
```
174+
175+
Usage:
176+
177+
```razor
178+
<!-- SomePage.cshtml -->
179+
180+
<card>
181+
<slot name=“header”>
182+
<strong>Laptop</strong>
183+
</slot>
184+
185+
Information about the product
186+
187+
<slot name=“footer”>
188+
<i>Price: $199</i>
189+
</slot>
190+
</card>
191+
```
192+
193+
Remarks:
194+
- `Model.Slot("header")` renders the content of passed through `<slot name=“header”>`
195+
- `Model.Slot("footer")` renders the content of passed through `<slot name=“footer”>`
196+
- `Model.Slot()` renders the rest of the child content
197+
198+
## Naming conventions
199+
200+
View tag helpers follow the ASP.NET Mvc Tag Helpers naming conventions, which means when
201+
the view tag helper has suffix `TagHelper`, the prefix in kebab-case will be used as the tag name. Example:
202+
203+
- `AlertTagHelper` gives `<alert />`.
204+
- `DisplayFieldTagHelper` gives `<display-field />`.
205+
206+
It's possible to not use the default convention and specify the tag names by using attributes, for example:
207+
208+
```c#
209+
// DisplayField.cshtml.cs
210+
211+
[HtmlTargetElement("DisplayField")]
212+
public class DisplayField : HydroTagHelper
213+
{
214+
public string Title { get; set; };
215+
}
216+
```
217+
218+
Usage:
219+
220+
```razor
221+
<!-- SomePage.cshtml -->
222+
223+
<DisplayField title="Price">
224+
199 EUR
225+
</DisplayField>
226+
```
227+
228+
## Differences between Hydro components and view tag helpers
229+
230+
**View tag helpers:**
231+
- Used to render views.
232+
- Not stateful or interactive.
233+
- Replacement for partial views, editors or regular view components.
234+
- Rerendered on each request.
235+
236+
**Hydro components:**
237+
- Used to render functional components.
238+
- Stateful and interactive.
239+
- Should be used when state is needed.
240+
- Rerendered only in specific situations, like action calls or events.

0 commit comments

Comments
 (0)