# Components ``` python from collections import UserDict from lxml import html as lx from pprint import pprint ``` ### Str and repr In notebooks, FT components are rendered as their syntax highlighted XML/HTML: ``` python sentence = P(Strong("FastHTML is ", I("Fast")), id='sentence_id') sentence ``` ``` html

FastHTML is Fast

``` Elsewhere, they are represented as their underlying data structure: ``` python print(repr(sentence)) ``` p((strong(('FastHTML is ', i(('Fast',),{})),{}),),{'id': 'sentence_id'}) ------------------------------------------------------------------------ source ### FT.\_\_str\_\_ > FT.__str__ () *Return str(self).* If they have an id, then that id is used as the component’s str representation: ``` python f'hx_target=#{sentence}' ``` 'hx_target=#sentence_id' ------------------------------------------------------------------------ source ### FT.\_\_radd\_\_ > FT.__radd__ (b) ``` python 'hx_target=#' + sentence ``` 'hx_target=#sentence_id' ------------------------------------------------------------------------ source ### FT.\_\_add\_\_ > FT.__add__ (b) ``` python sentence + '...' ``` 'sentence_id...' ### fh_html and fh_hx ------------------------------------------------------------------------ source ### attrmap_x > attrmap_x (o) ------------------------------------------------------------------------ source ### ft_html > ft_html (tag:str, *c, id=None, cls=None, title=None, style=None, > attrmap=None, valmap=None, ft_cls=None, **kwargs) ``` python ft_html('a', **{'@click.away':1}) ``` ``` html ``` ``` python ft_html('a', {'@click.away':1}) ``` ``` html ``` ``` python ft_html('a', UserDict({'@click.away':1})) ``` ``` html ``` ``` python c = Div(id='someid') ``` ``` python ft_html('a', id=c) ``` ``` html ``` ------------------------------------------------------------------------ source ### ft_hx > ft_hx (tag:str, *c, target_id=None, hx_vals=None, hx_target=None, > id=None, cls=None, title=None, style=None, accesskey=None, > contenteditable=None, dir=None, draggable=None, enterkeyhint=None, > hidden=None, inert=None, inputmode=None, lang=None, popover=None, > spellcheck=None, tabindex=None, translate=None, hx_get=None, > hx_post=None, hx_put=None, hx_delete=None, hx_patch=None, > hx_trigger=None, hx_swap=None, hx_swap_oob=None, hx_include=None, > hx_select=None, hx_select_oob=None, hx_indicator=None, > hx_push_url=None, hx_confirm=None, hx_disable=None, > hx_replace_url=None, hx_disabled_elt=None, hx_ext=None, > hx_headers=None, hx_history=None, hx_history_elt=None, > hx_inherit=None, hx_params=None, hx_preserve=None, hx_prompt=None, > hx_request=None, hx_sync=None, hx_validate=None, hx_on_blur=None, > hx_on_change=None, hx_on_contextmenu=None, hx_on_focus=None, > hx_on_input=None, hx_on_invalid=None, hx_on_reset=None, > hx_on_select=None, hx_on_submit=None, hx_on_keydown=None, > hx_on_keypress=None, hx_on_keyup=None, hx_on_click=None, > hx_on_dblclick=None, hx_on_mousedown=None, hx_on_mouseenter=None, > hx_on_mouseleave=None, hx_on_mousemove=None, hx_on_mouseout=None, > hx_on_mouseover=None, hx_on_mouseup=None, hx_on_wheel=None, > hx_on__abort=None, hx_on__after_on_load=None, > hx_on__after_process_node=None, hx_on__after_request=None, > hx_on__after_settle=None, hx_on__after_swap=None, > hx_on__before_cleanup_element=None, hx_on__before_on_load=None, > hx_on__before_process_node=None, hx_on__before_request=None, > hx_on__before_swap=None, hx_on__before_send=None, > hx_on__before_transition=None, hx_on__config_request=None, > hx_on__confirm=None, hx_on__history_cache_error=None, > hx_on__history_cache_miss=None, > hx_on__history_cache_miss_error=None, > hx_on__history_cache_miss_load=None, hx_on__history_restore=None, > hx_on__before_history_save=None, hx_on__load=None, > hx_on__no_sse_source_error=None, hx_on__on_load_error=None, > hx_on__oob_after_swap=None, hx_on__oob_before_swap=None, > hx_on__oob_error_no_target=None, hx_on__prompt=None, > hx_on__pushed_into_history=None, hx_on__replaced_in_history=None, > hx_on__response_error=None, hx_on__send_abort=None, > hx_on__send_error=None, hx_on__sse_error=None, > hx_on__sse_open=None, hx_on__swap_error=None, > hx_on__target_error=None, hx_on__timeout=None, > hx_on__validation_validate=None, hx_on__validation_failed=None, > hx_on__validation_halted=None, hx_on__xhr_abort=None, > hx_on__xhr_loadend=None, hx_on__xhr_loadstart=None, > hx_on__xhr_progress=None, **kwargs) ``` python ft_hx('a', hx_vals={'a':1}) ``` ``` html ``` ``` python ft_hx('a', hx_target=c) ``` ``` html ``` For tags that have a `name` attribute, it will be set to the value of `id` if not provided explicitly: ``` python Form(Button(target_id='foo', id='btn'), hx_post='/', target_id='tgt', id='frm') ``` ``` html
``` ------------------------------------------------------------------------ source ### File > File (fname) *Use the unescaped text in file `fname` directly* ``` python a = Input(name='nm') a ``` ``` html ``` ``` python a(hx_swap_oob='true') ``` ``` html ``` ``` python a ``` ``` html ``` ### show ------------------------------------------------------------------------ source ### show > show (ft, *rest, iframe=False, height='auto', style=None) *Renders FT Components into HTML within a Jupyter notebook.* When placed within the [`show()`](https://www.fastht.ml/docs/api/components.html#show) function, this will render the HTML in Jupyter notebooks. ``` python show(sentence) ```

FastHTML is Fast

You can also display full embedded pages in an iframe: ``` python picocss = "https://cdn.jsdelivr.net/npm/@picocss/pico@latest/css/pico.min.css" picolink = (Link(rel="stylesheet", href=picocss)) fullpage = Html( Head(picolink), Body( H2("Heading 2"), P("Paragraph") ) ) show(fullpage, height=100, iframe=True) ``` ### fill_form and find_inputs ------------------------------------------------------------------------ source ### fill_form > fill_form (form:fastcore.xml.FT, obj) *Fills named items in `form` using attributes in `obj`* ``` python @dataclass class TodoItem: title:str; id:int; done:bool; details:str; opt:str='a' todo = TodoItem(id=2, title="Profit", done=True, details="Details", opt='b') check = Label(Input(type="checkbox", cls="checkboxer", name="done", data_foo="bar"), "Done", cls='px-2') form = Form(Fieldset(Input(cls="char", id="title", value="a"), check, Input(type="hidden", id="id"), Select(Option(value='a'), Option(value='b'), name='opt'), Textarea(id='details'), Button("Save"), name="stuff")) form = fill_form(form, todo) assert '' in to_xml(form) form ``` ``` html
``` ``` python @dataclass class MultiSelect: items: list[str] multiselect = MultiSelect(items=['a', 'c']) multiform = Form(Select(Option('a', value='a'), Option('b', value='b'), Option('c', value='c'), multiple='1', name='items')) multiform = fill_form(multiform, multiselect) assert '' in to_xml(multiform) assert '' in to_xml(multiform) assert '' in to_xml(multiform) multiform ``` ``` html
``` ``` python @dataclass class MultiCheck: items: list[str] multicheck = MultiCheck(items=['a', 'c']) multiform = Form(Fieldset(Label(Input(type='checkbox', name='items', value='a'), 'a'), Label(Input(type='checkbox', name='items', value='b'), 'b'), Label(Input(type='checkbox', name='items', value='c'), 'c'))) multiform = fill_form(multiform, multicheck) assert '' in to_xml(multiform) assert '' in to_xml(multiform) assert '' in to_xml(multiform) multiform ``` ``` html
``` ------------------------------------------------------------------------ source ### fill_dataclass > fill_dataclass (src, dest) *Modifies dataclass in-place and returns it* ``` python nt = TodoItem('', 0, False, '') fill_dataclass(todo, nt) nt ``` TodoItem(title='Profit', id=2, done=True, details='Details', opt='b') ------------------------------------------------------------------------ source ### find_inputs > find_inputs (e, tags='input', **kw) *Recursively find all elements in `e` with `tags` and attrs matching `kw`* ``` python inps = find_inputs(form, id='title') test_eq(len(inps), 1) inps ``` [input((),{'value': 'Profit', 'id': 'title', 'class': 'char', 'name': 'title'})] You can also use lxml for more sophisticated searching: ``` python elem = lx.fromstring(to_xml(form)) test_eq(elem.xpath("//input[@id='title']/@value"), ['Profit']) ``` ------------------------------------------------------------------------ source ### **getattr** > __getattr__ (tag) ### html2ft ------------------------------------------------------------------------ source ### html2ft > html2ft (html, attr1st=False) *Convert HTML to an `ft` expression* ``` python h = to_xml(form) hl_md(html2ft(h), 'python') ``` ``` python Form( Fieldset( Input(value='Profit', id='title', name='title', cls='char'), Label( Input(type='checkbox', name='done', data_foo='bar', checked='1', cls='checkboxer'), 'Done', cls='px-2' ), Input(type='hidden', id='id', name='id', value='2'), Select( Option(value='a'), Option(value='b', selected='1'), name='opt' ), Textarea('Details', id='details', name='details'), Button('Save'), name='stuff' ) ) ``` ``` python hl_md(html2ft(h, attr1st=True), 'python') ``` ``` python Form( Fieldset(name='stuff')( Input(value='Profit', id='title', name='title', cls='char')(), Label(cls='px-2')( Input(type='checkbox', name='done', data_foo='bar', checked='1', cls='checkboxer')(), 'Done' ), Input(type='hidden', id='id', name='id', value='2')(), Select(name='opt')( Option(value='a')(), Option(value='b', selected='1')() ), Textarea(id='details', name='details')('Details'), Button()('Save') ) ) ``` ------------------------------------------------------------------------ source ### sse_message > sse_message (elm, event='message') *Convert element `elm` into a format suitable for SSE streaming* ``` python print(sse_message(Div(P('hi'), P('there')))) ``` event: message data:
data:

hi

data:

there

data:
## Tests ``` python test_html2ft('', attr1st=True) test_html2ft('') test_html2ft('
') test_html2ft('
hi
') test_html2ft('
Hello 👋
') test_html2ft('
hello
') ``` ``` python assert html2ft('
hi
', attr1st=True) == "Div(id='foo')('hi')" assert html2ft("""
Hello 👋
""") == "Div('Hello 👋', x_show='open', **{'x-transition:enter': 'transition duration-300', 'x-transition:enter-start': 'opacity-0 scale-90'})" assert html2ft('
hello
') == "Div('hello', **{'x-transition:enter.scale.80': True, 'x-transition:leave.scale.90': True})" assert html2ft(" ") == "Img(alt=' ')" ```