from fasthtml.common import NotStr,Div, to_xml
Custom Components
The majority of the time the default ft components are all you need (for example Div
, P
, H1
, etc.).
If you don’t know what an ft component is, you should read the explaining ft components explainer first.
However, there are many situations where you need a custom ft component that creates a unique HTML tag (for example <zero-md></zero-md>
). There are many options in FastHTML to do this, and this section will walk through them. Generally you want to use the highest level option that fits your needs.
This external tutorial walks through a practical situation where you may want to create a custom HTML tag using a custom ft component. Seeing a real-world example is a good way to understand why the contents of this guide is useful.
NotStr
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.
= NotStr('<div></div>')
div_NotStr print(div_NotStr)
<div></div>
Automatic Creation
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).
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.
from fasthtml.components import Some_never_before_used_tag
Some_never_before_used_tag()
<some-never-before-used-tag></some-never-before-used-tag>
Manual Creation
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.
import fasthtml
= fasthtml.components.Some_never_before_used_tag()
auto_called = fasthtml.components.__getattr__('Some_never_before_used_tag')()
manual_called
# Proving they generate the same xml
assert to_xml(auto_called) == to_xml(manual_called)
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.
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).
In a module __getattr__
is called to get an attribute. In fasthtml.components
, this is defined to create components automatically for you.
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.
from fasthtml.common import ft_hx
def ft_path(*c, target_id=None, **kwargs):
return ft_hx('path', *c, target_id=target_id, **kwargs)
ft_path()
<path></path>
We can add any behavior in that function that we need to, so let’s go through some progressively complex examples that you may need in some of your projects.
Symbols (ie @) in tag attributes
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.
='normal stuff',**{'notNormal:arg:with_varing@symbols!':'123'}) Div(normal_arg
<div normal-arg="normal stuff" notnormal:arg:with_varing@symbols!="123"></div>