Components

ft_html and ft_hx functions to add some conveniences to ft, along with a full set of basic HTML components, and functions to work with forms and FT conversion
from lxml import html as lx
from pprint import pprint

Str, show and repr


source

show

 show (ft, *rest)

Renders FT Components into HTML within a Jupyter notebook.

sentence = P(Strong("FastHTML is ", I("Fast")), id='sentence_id')

When placed within the show() function, this will render the HTML in Jupyter notebooks.

show(sentence)

FastHTML is Fast

In notebooks, FT components are rendered as their syntax highlighted XML/HTML:

sentence
<p id="sentence_id">
<strong>FastHTML is <i>Fast</i></strong></p>

Elsewhere, they are represented as their underlying data structure:

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:

f'hx_target=#{sentence}'
'hx_target=#sentence_id'

source

FT.__radd__

 FT.__radd__ (b)
'hx_target=#' + sentence
'hx_target=#sentence_id'

source

FT.__add__

 FT.__add__ (b)
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)
ft_html('a', **{'@click.away':1})
<a @click.away="1"></a>
ft_html('a', {'@click.away':1})
<a @click.away="1"></a>
c = Div(id='someid')
ft_html('a', id=c)
<a id="someid" name="someid"></a>

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, **kwargs)
ft_hx('a', hx_vals={'a':1})
<a hx-vals='{"a": 1}'></a>
ft_hx('a', hx_target=c)
<a hx-target="#someid"></a>

For tags that have a name attribute, it will be set to the value of id if not provided explicitly:

Form(Button(target_id='foo', id='btn'),
     hx_post='/', target_id='tgt', id='frm')
<form hx-post="/" hx-target="#tgt" id="frm" name="frm"><button hx-target="#foo" id="btn" name="btn"></button></form>

source

File

 File (fname)

Use the unescaped text in file fname directly

a = Input(name='nm')
a
<input name="nm">
a(hx_swap_oob='true')
<input name="nm" hx-swap-oob="true">
a
<input name="nm" hx-swap-oob="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

@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 '<textarea id="details" name="details">Details</textarea>' in to_xml(form)
form
<form><fieldset name="stuff">    <input value="Profit" id="title" class="char" name="title">
<label class="px-2">      <input type="checkbox" name="done" data-foo="bar" class="checkboxer" checked="1">
Done</label>    <input type="hidden" id="id" name="id" value="2">
<select name="opt"><option value="a"></option><option value="b" selected="1"></option></select><textarea id="details" name="details">Details</textarea><button>Save</button></fieldset></form>
@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 '<option value="a" selected="1">a</option>' in to_xml(multiform)
assert '<option value="b">b</option>' in to_xml(multiform)
assert '<option value="c" selected="1">c</option>' in to_xml(multiform)
multiform
<form><select multiple="1" name="items"><option value="a" selected="1">a</option><option value="b">b</option><option value="c" selected="1">c</option></select></form>
@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 '<input type="checkbox" name="items" value="a" checked="1">' in to_xml(multiform)
assert '<input type="checkbox" name="items" value="b">' in to_xml(multiform)
assert '<input type="checkbox" name="items" value="c" checked="1">' in to_xml(multiform)
multiform
<form><fieldset><label>      <input type="checkbox" name="items" value="a" checked="1">
a</label><label>      <input type="checkbox" name="items" value="b">
b</label><label>      <input type="checkbox" name="items" value="c" checked="1">
c</label></fieldset></form>

source

fill_dataclass

 fill_dataclass (src, dest)

Modifies dataclass in-place and returns it

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

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:

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

h = to_xml(form)
hl_md(html2ft(h), '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'
    )
)
hl_md(html2ft(h, attr1st=True), '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

print(sse_message(Div(P('hi'), P('there'))))
event: message
data: <div>
data:   <p>hi</p>
data:   <p>there</p>
data: </div>

Tests

test_html2ft('<input value="Profit" name="title" id="title" class="char">', attr1st=True)
test_html2ft('<input value="Profit" name="title" id="title" class="char">')
test_html2ft('<div id="foo"></div>')
test_html2ft('<div id="foo">hi</div>')
test_html2ft('<div x-show="open" x-transition:enter="transition duration-300" x-transition:enter-start="opacity-0 scale-90">Hello ๐Ÿ‘‹</div>')
test_html2ft('<div x-transition:enter.scale.80 x-transition:leave.scale.90>hello</div>')
assert html2ft('<div id="foo">hi</div>', attr1st=True) == "Div(id='foo')('hi')"
assert html2ft("""
  <div x-show="open" x-transition:enter="transition duration-300" x-transition:enter-start="opacity-0 scale-90">Hello ๐Ÿ‘‹</div>
""") == "Div('Hello ๐Ÿ‘‹', x_show='open', **{'x-transition:enter': 'transition duration-300', 'x-transition:enter-start': 'opacity-0 scale-90'})"
assert html2ft('<div x-transition:enter.scale.80 x-transition:leave.scale.90>hello</div>') == "Div('hello', **{'x-transition:enter.scale.80': True, 'x-transition:leave.scale.90': True})"
assert html2ft("<img alt=' ' />") == "Img(alt=' ')"