Skip to content

Commit 556b5b2

Browse files
authored
Merge pull request #753 from pydanny/improve-custom-components-docs
Improvements to the custom components docs
2 parents b60ddd2 + deda414 commit 556b5b2

File tree

1 file changed

+78
-68
lines changed

1 file changed

+78
-68
lines changed

nbs/ref/defining_xt_component.ipynb

Lines changed: 78 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -32,45 +32,14 @@
3232
"cell_type": "markdown",
3333
"metadata": {},
3434
"source": [
35-
"## NotStr\n",
36-
"\n",
37-
"The first way is to use the `NotStr` class to use an HTML tag as a string. It works as a one-off but quickly becomes harder to work with as complexity grows. However we can see that you can genenrate the same xml using `NotStr` as the out-of-the-box components."
38-
]
39-
},
40-
{
41-
"cell_type": "code",
42-
"execution_count": null,
43-
"metadata": {},
44-
"outputs": [],
45-
"source": [
46-
"from fasthtml.common import NotStr,Div, to_xml"
47-
]
48-
},
49-
{
50-
"cell_type": "code",
51-
"execution_count": null,
52-
"metadata": {},
53-
"outputs": [
54-
{
55-
"name": "stdout",
56-
"output_type": "stream",
57-
"text": [
58-
"<div></div>\n"
59-
]
60-
}
61-
],
62-
"source": [
63-
"div_NotStr = NotStr('<div></div>') \n",
64-
"print(div_NotStr)"
35+
"## Automatic Creation"
6536
]
6637
},
6738
{
6839
"cell_type": "markdown",
6940
"metadata": {},
7041
"source": [
71-
"## Automatic Creation\n",
72-
"\n",
73-
"The next (and better) approach is to let FastHTML generate the component function for you. As you can see in our `assert` this creates a function that creates the HTML just as we wanted. This works even though there is not a `Some_never_before_used_tag` function in the `fasthtml.components` source code (you can verify this yourself by looking at the source code). \n",
42+
"The first (and in most cases the best) approach is to let FastHTML generate the component function for you. As you can see in our `assert` this creates a function that creates the HTML just as we wanted. This works even though there is not a `Some_never_before_used_tag` function in the `fasthtml.components` source code (you can verify this yourself by looking at the source code). \n",
7443
"\n",
7544
":::{.callout-tip}\n",
7645
"Typically these tags are needed because a CSS or Javascript library created a new XML tag that isn't default HTML. For example the `zero-md` javascript library looks for a `<zero-md></zero-md>` tag to know what to run its javascript code on. Most CSS libraries work by creating styling based on the `class` attribute, but they can also apply styling to an arbitrary HTML tag that they made up.\n",
@@ -108,52 +77,25 @@
10877
"cell_type": "markdown",
10978
"metadata": {},
11079
"source": [
111-
"## Manual Creation"
112-
]
113-
},
114-
{
115-
"cell_type": "markdown",
116-
"metadata": {},
117-
"source": [
118-
"The automatic creation isn't magic. It's just calling a python function `__getattr__` and you can call it yourself to get the same result."
119-
]
120-
},
121-
{
122-
"cell_type": "code",
123-
"execution_count": null,
124-
"metadata": {},
125-
"outputs": [],
126-
"source": [
127-
"import fasthtml\n",
128-
"\n",
129-
"auto_called = fasthtml.components.Some_never_before_used_tag()\n",
130-
"manual_called = fasthtml.components.__getattr__('Some_never_before_used_tag')()\n",
80+
":::{.callout-tip}\n",
81+
"In a module `__getattr__` is called to get an attribute. In `fasthtml.components`, the `__getattr__` is set to create components automatically for you.\n",
13182
"\n",
132-
"# Proving they generate the same xml\n",
133-
"assert to_xml(auto_called) == to_xml(manual_called)"
83+
"Dunder methods and functions are special functions that have double underscores at the beginning and end of their name. They are called at specific times in python so you can use them to cause customized behavior that makes sense for your specific use case. They can appear magical if you don't know how python works, but they are extremely commonly used to modify python's default behavior (`__init__` is probably the most common one).\n",
84+
":::"
13485
]
13586
},
13687
{
13788
"cell_type": "markdown",
13889
"metadata": {},
13990
"source": [
140-
"Knowing that, we know that it's possible to create a different function that has different behavior than FastHTMLs default behavior by modifying how the `___getattr__` function creates the components! It's only a few lines of code and reading that what it does is a great way to understand components more deeply.\n",
141-
"\n"
91+
"## Manual Creation"
14292
]
14393
},
14494
{
14595
"cell_type": "markdown",
14696
"metadata": {},
14797
"source": [
148-
":::{.callout-tip}\n",
149-
"\n",
150-
"Dunder methods and functions are special functions that have double underscores at the beginning and end of their name. They are called at specific times in python so you can use them to cause customized behavior that makes sense for your specific use case. They can appear magical if you don't know how python works, but they are extremely commonly used to modify python's default behavior (`__init__` is probably the most common one).\n",
151-
"\n",
152-
"In a module `__getattr__` is called to get an attribute. In `fasthtml.components`, this is defined to create components automatically for you.\n",
153-
":::\n",
154-
"\n",
155-
"\n",
156-
"For example if you want a component that creates `<path></path>` that doesn't conflict names with `pathlib.Path` you can do that. FastHTML automatically creates new components with a 1:1 mapping and a consistent name, which is almost always what you want. But in some cases you may want to customize that and you can use the `ft_hx` function to do that differently than the default."
98+
"If you want a component that creates `<path></path>` that doesn't conflict names with `pathlib.Path` you can do that. FastHTML automatically creates new components with a 1:1 mapping and a consistent name, which is almost always what you want. But in some cases you may want to customize that and you can use the `ft_hx` function to do that differently than the default."
15799
]
158100
},
159101
{
@@ -186,6 +128,13 @@
186128
"ft_path()\n"
187129
]
188130
},
131+
{
132+
"cell_type": "markdown",
133+
"metadata": {},
134+
"source": [
135+
"## Special Cases"
136+
]
137+
},
189138
{
190139
"cell_type": "markdown",
191140
"metadata": {},
@@ -232,7 +181,7 @@
232181
"def tag_with_underscores(*c, target_id=None, **kwargs): \n",
233182
" return ft_hx('tag_with_underscores', *c, target_id=target_id, **kwargs)\n",
234183
"\n",
235-
"tag_with_underscores()\n"
184+
"tag_with_underscores()"
236185
]
237186
},
238187
{
@@ -271,7 +220,6 @@
271220
}
272221
],
273222
"source": [
274-
"\n",
275223
"def tag_with_AtSymbol(*c, target_id=None, **kwargs): \n",
276224
" return ft_hx('tag-with-@symbol', *c, target_id=target_id, **kwargs)\n",
277225
"\n",
@@ -292,6 +240,15 @@
292240
"It also may be that an argument in an HTML tag uses characters that can't be used in python arguments. To handle these you can define those args using a dictionary."
293241
]
294242
},
243+
{
244+
"cell_type": "code",
245+
"execution_count": null,
246+
"metadata": {},
247+
"outputs": [],
248+
"source": [
249+
"from fasthtml.common import Div"
250+
]
251+
},
295252
{
296253
"cell_type": "code",
297254
"execution_count": null,
@@ -317,6 +274,59 @@
317274
"source": [
318275
"Div(normal_arg='normal stuff',**{'notNormal:arg:with_varing@symbols!':'123'})"
319276
]
277+
},
278+
{
279+
"cell_type": "markdown",
280+
"metadata": {},
281+
"source": [
282+
"## In Desperation: NotStr"
283+
]
284+
},
285+
{
286+
"cell_type": "markdown",
287+
"metadata": {},
288+
"source": [
289+
"An uncommon method is to use the `NotStr` class writing the HTML tag as a string. It works as a one-off for a quickfix but quickly becomes harder to work with as complexity grows. However we can see that you can with some effort generate a similar result with `to_xml` using `NotStr` as the out-of-the-box components.\n",
290+
"\n",
291+
"Try everything else before using `NotStr` and if you must use it we recommend returning later and fixing it to use one of the above techniques."
292+
]
293+
},
294+
{
295+
"cell_type": "code",
296+
"execution_count": null,
297+
"metadata": {},
298+
"outputs": [],
299+
"source": [
300+
"from fasthtml.common import NotStr,to_xml"
301+
]
302+
},
303+
{
304+
"cell_type": "code",
305+
"execution_count": null,
306+
"metadata": {},
307+
"outputs": [
308+
{
309+
"data": {
310+
"text/plain": [
311+
"'<div>I look like a string but render with to_xml</div>'"
312+
]
313+
},
314+
"execution_count": null,
315+
"metadata": {},
316+
"output_type": "execute_result"
317+
}
318+
],
319+
"source": [
320+
"div_NotStr = NotStr('<div>I look like a string but render with to_xml</div>') \n",
321+
"to_xml(div_NotStr)"
322+
]
323+
},
324+
{
325+
"cell_type": "code",
326+
"execution_count": null,
327+
"metadata": {},
328+
"outputs": [],
329+
"source": []
320330
}
321331
],
322332
"metadata": {

0 commit comments

Comments
 (0)