or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collections.mdcore-utilities.mdextended.mdindex.mdmetaprogramming.mdnetworking.mdparallel.mdsystem-integration.mdtesting.mdxml-html.md

xml-html.mddocs/

0

# HTML/XML Generation

1

2

Programmatic HTML and XML generation with a fluent API, supporting all standard HTML elements and providing safe string handling for web development. The xml module enables building HTML documents and web components through Python code with type safety and modern web standards support.

3

4

## Capabilities

5

6

### Core XML/HTML Generation

7

8

Fundamental classes for creating and manipulating XML/HTML structures with a fluent, chainable API.

9

10

```python { .api }

11

class FT:

12

"""

13

Fast Tag - Core class for XML/HTML element creation and manipulation.

14

15

Provides a flexible, chainable interface for building HTML/XML structures

16

with automatic attribute handling, content management, and event system.

17

18

Features:

19

- Chainable method calls for fluent API

20

- Automatic attribute name conversion (class_, htmlClass -> class)

21

- Event listener system for dynamic updates

22

- Support for nested elements and content

23

- Void element handling (self-closing tags)

24

25

Parameters:

26

- tag: str, HTML/XML tag name

27

- cs: tuple, child elements and content

28

- attrs: dict, element attributes

29

- void_: bool, whether element is self-closing

30

- **kwargs: additional attributes

31

"""

32

33

def __init__(self, tag, cs, attrs=None, void_=False, **kwargs): ...

34

35

def __call__(self, *c, **kw):

36

"""

37

Add children and/or attributes (chainable).

38

39

Parameters:

40

- *c: child elements or content to add

41

- **kw: attributes to set

42

43

Returns:

44

self: For method chaining

45

"""

46

47

def set(self, *c, **kw):

48

"""

49

Set children and/or attributes, replacing existing (chainable).

50

51

Parameters:

52

- *c: child elements or content to set

53

- **kw: attributes to set

54

55

Returns:

56

self: For method chaining

57

"""

58

59

def get(self, k, default=None):

60

"""

61

Get attribute value.

62

63

Parameters:

64

- k: str, attribute name

65

- default: default value if attribute not found

66

67

Returns:

68

Attribute value or default

69

"""

70

71

def on(self, f):

72

"""

73

Add event listener for element changes.

74

75

Parameters:

76

- f: callable, listener function called on changes

77

"""

78

79

def changed(self):

80

"""

81

Notify listeners of element changes and return self.

82

83

Returns:

84

self: For method chaining

85

"""

86

87

# Properties and indexing

88

@property

89

def list(self):

90

"""Get [tag, children, attrs] representation."""

91

92

def __getitem__(self, idx): ...

93

def __setitem__(self, i, o): ...

94

def __iter__(self): ...

95

96

def ft(tag, *c, **kw):

97

"""

98

Create FT (Fast Tag) element with specified tag, content, and attributes.

99

100

Convenient factory function for creating HTML/XML elements with

101

automatic preprocessing of content and attributes.

102

103

Parameters:

104

- tag: str, HTML/XML tag name

105

- *c: child elements, strings, or other content

106

- **kw: element attributes (automatically converted)

107

108

Returns:

109

FT: Configured element ready for use

110

111

Examples:

112

div = ft('div', 'Hello World', class_='container')

113

link = ft('a', 'Click here', href='https://example.com')

114

"""

115

116

def Html(*c, **kwargs):

117

"""

118

Create complete HTML document structure.

119

120

Generates proper HTML5 document with DOCTYPE and html root element.

121

Automatically handles head and body sections if provided.

122

123

Parameters:

124

- *c: content for the document (head, body, or direct elements)

125

- **kwargs: attributes for html element (lang, etc.)

126

127

Returns:

128

str: Complete HTML document string

129

"""

130

131

class Safe:

132

"""

133

Wrapper for HTML strings that should not be escaped.

134

135

Used to mark strings as safe HTML content that should be

136

inserted directly without HTML entity escaping.

137

138

Parameters:

139

- s: str, HTML content that is safe to insert directly

140

141

Usage:

142

content = Safe('<strong>Bold text</strong>')

143

div = Div(content) # HTML is not escaped

144

"""

145

146

def __init__(self, s): ...

147

148

def to_xml(elm, lvl=0):

149

"""

150

Convert element tree to XML/HTML string representation.

151

152

Serializes FT elements and nested structures to properly

153

formatted XML/HTML with appropriate indentation and escaping.

154

155

Parameters:

156

- elm: FT element or content to serialize

157

- lvl: int, indentation level for formatting

158

159

Returns:

160

str: XML/HTML string representation

161

"""

162

```

163

164

### Attribute and Value Processing

165

166

Utilities for handling HTML attributes and values with proper conversion and escaping.

167

168

```python { .api }

169

def attrmap(o):

170

"""

171

Map Python attribute names to HTML attribute names.

172

173

Converts Python-friendly attribute names to proper HTML attributes:

174

- class_, cls, htmlClass, klass -> class

175

- _for, fr, htmlFor -> for

176

- Leading underscores removed: _id -> id

177

- Underscores converted to hyphens: data_value -> data-value

178

179

Parameters:

180

- o: str, attribute name to convert

181

182

Returns:

183

str: HTML-compatible attribute name

184

"""

185

186

def valmap(o):

187

"""

188

Convert Python values to HTML attribute values.

189

190

Handles various Python types for HTML attribute values:

191

- Lists: joined with spaces (['btn', 'primary'] -> 'btn primary')

192

- Dicts: CSS-style ({"color": "red"} -> 'color:red')

193

- None/empty: returns None (attribute omitted)

194

195

Parameters:

196

- o: value to convert to HTML attribute format

197

198

Returns:

199

str|None: HTML-compatible attribute value or None

200

"""

201

202

voids = {

203

"""

204

Set of HTML void elements (self-closing tags).

205

206

Contains all HTML elements that don't have closing tags:

207

area, base, br, col, embed, hr, img, input, link, meta,

208

param, source, track, wbr

209

210

Used automatically by element creation functions to determine

211

whether to generate self-closing tags.

212

"""

213

}

214

```

215

216

### HTML Element Classes

217

218

Pre-configured classes for all standard HTML elements with appropriate default behaviors.

219

220

```python { .api }

221

# Document structure elements

222

def Head(*c, **kwargs):

223

"""HTML head element for document metadata."""

224

225

def Title(*c, **kwargs):

226

"""HTML title element for document title."""

227

228

def Meta(*c, **kwargs):

229

"""HTML meta element for metadata (void element)."""

230

231

def Link(*c, **kwargs):

232

"""HTML link element for external resources (void element)."""

233

234

def Style(*c, **kwargs):

235

"""HTML style element for embedded CSS."""

236

237

def Body(*c, **kwargs):

238

"""HTML body element for document content."""

239

240

# Text content elements

241

def P(*c, **kwargs):

242

"""HTML paragraph element."""

243

244

def Div(*c, **kwargs):

245

"""HTML div element for generic container."""

246

247

def Span(*c, **kwargs):

248

"""HTML span element for inline content."""

249

250

def Pre(*c, **kwargs):

251

"""HTML pre element for preformatted text."""

252

253

def Code(*c, **kwargs):

254

"""HTML code element for code snippets."""

255

256

# Heading elements

257

def H1(*c, **kwargs):

258

"""HTML h1 element for main heading."""

259

260

def H2(*c, **kwargs):

261

"""HTML h2 element for secondary heading."""

262

263

def H3(*c, **kwargs):

264

"""HTML h3 element for tertiary heading."""

265

266

def H4(*c, **kwargs):

267

"""HTML h4 element for quaternary heading."""

268

269

def H5(*c, **kwargs):

270

"""HTML h5 element for quinary heading."""

271

272

def H6(*c, **kwargs):

273

"""HTML h6 element for senary heading."""

274

275

# Text formatting elements

276

def Strong(*c, **kwargs):

277

"""HTML strong element for strong importance."""

278

279

def Em(*c, **kwargs):

280

"""HTML em element for emphasized text."""

281

282

def B(*c, **kwargs):

283

"""HTML b element for bold text."""

284

285

def I(*c, **kwargs):

286

"""HTML i element for italic text."""

287

288

def U(*c, **kwargs):

289

"""HTML u element for underlined text."""

290

291

def S(*c, **kwargs):

292

"""HTML s element for strikethrough text."""

293

294

def Strike(*c, **kwargs):

295

"""HTML strike element (deprecated, use S)."""

296

297

def Sub(*c, **kwargs):

298

"""HTML sub element for subscript text."""

299

300

def Sup(*c, **kwargs):

301

"""HTML sup element for superscript text."""

302

303

def Mark(*c, **kwargs):

304

"""HTML mark element for highlighted text."""

305

306

def Small(*c, **kwargs):

307

"""HTML small element for smaller text."""

308

309

# Structure elements

310

def Hr(*c, **kwargs):

311

"""HTML hr element for thematic break (void element)."""

312

313

def Br(*c, **kwargs):

314

"""HTML br element for line break (void element)."""

315

316

# Media elements

317

def Img(*c, **kwargs):

318

"""HTML img element for images (void element)."""

319

320

def Video(*c, **kwargs):

321

"""HTML video element for video content."""

322

323

def Audio(*c, **kwargs):

324

"""HTML audio element for audio content."""

325

326

def Source(*c, **kwargs):

327

"""HTML source element for media resources (void element)."""

328

329

def Canvas(*c, **kwargs):

330

"""HTML canvas element for graphics."""

331

332

def Svg(*c, **kwargs):

333

"""HTML svg element for vector graphics."""

334

335

def Iframe(*c, **kwargs):

336

"""HTML iframe element for embedded content."""

337

338

def Object(*c, **kwargs):

339

"""HTML object element for embedded objects."""

340

341

def Embed(*c, **kwargs):

342

"""HTML embed element for embedded content (void element)."""

343

344

def Param(*c, **kwargs):

345

"""HTML param element for object parameters (void element)."""

346

347

# Navigation and linking

348

def A(*c, **kwargs):

349

"""HTML a element for hyperlinks."""

350

351

def Nav(*c, **kwargs):

352

"""HTML nav element for navigation links."""

353

354

# List elements

355

def Ul(*c, **kwargs):

356

"""HTML ul element for unordered lists."""

357

358

def Ol(*c, **kwargs):

359

"""HTML ol element for ordered lists."""

360

361

def Li(*c, **kwargs):

362

"""HTML li element for list items."""

363

364

def Dl(*c, **kwargs):

365

"""HTML dl element for description lists."""

366

367

def Dt(*c, **kwargs):

368

"""HTML dt element for description terms."""

369

370

def Dd(*c, **kwargs):

371

"""HTML dd element for description details."""

372

373

# Table elements

374

def Table(*c, **kwargs):

375

"""HTML table element for tabular data."""

376

377

def Thead(*c, **kwargs):

378

"""HTML thead element for table header."""

379

380

def Tbody(*c, **kwargs):

381

"""HTML tbody element for table body."""

382

383

def Tfoot(*c, **kwargs):

384

"""HTML tfoot element for table footer."""

385

386

def Tr(*c, **kwargs):

387

"""HTML tr element for table rows."""

388

389

def Th(*c, **kwargs):

390

"""HTML th element for table headers."""

391

392

def Td(*c, **kwargs):

393

"""HTML td element for table data."""

394

395

def Caption(*c, **kwargs):

396

"""HTML caption element for table captions."""

397

398

def Col(*c, **kwargs):

399

"""HTML col element for table columns (void element)."""

400

401

def Colgroup(*c, **kwargs):

402

"""HTML colgroup element for column groups."""

403

404

# Form elements

405

def Form(*c, **kwargs):

406

"""HTML form element for user input forms."""

407

408

def Input(*c, **kwargs):

409

"""HTML input element for form inputs (void element)."""

410

411

def Textarea(*c, **kwargs):

412

"""HTML textarea element for multi-line text input."""

413

414

def Button(*c, **kwargs):

415

"""HTML button element for clickable buttons."""

416

417

def Select(*c, **kwargs):

418

"""HTML select element for dropdown selections."""

419

420

def Option(*c, **kwargs):

421

"""HTML option element for select options."""

422

423

def Label(*c, **kwargs):

424

"""HTML label element for form labels."""

425

426

def Fieldset(*c, **kwargs):

427

"""HTML fieldset element for form grouping."""

428

429

def Legend(*c, **kwargs):

430

"""HTML legend element for fieldset captions."""

431

432

# Semantic structure elements

433

def Main(*c, **kwargs):

434

"""HTML main element for main content."""

435

436

def Header(*c, **kwargs):

437

"""HTML header element for introductory content."""

438

439

def Footer(*c, **kwargs):

440

"""HTML footer element for footer content."""

441

442

def Section(*c, **kwargs):

443

"""HTML section element for document sections."""

444

445

def Article(*c, **kwargs):

446

"""HTML article element for standalone content."""

447

448

def Aside(*c, **kwargs):

449

"""HTML aside element for sidebar content."""

450

451

def Figure(*c, **kwargs):

452

"""HTML figure element for figure content."""

453

454

def Figcaption(*c, **kwargs):

455

"""HTML figcaption element for figure captions."""

456

457

# Interactive elements

458

def Details(*c, **kwargs):

459

"""HTML details element for disclosure widget."""

460

461

def Summary(*c, **kwargs):

462

"""HTML summary element for details summary."""

463

464

# Scripting elements

465

def Script(*c, **kwargs):

466

"""HTML script element for JavaScript."""

467

468

def Noscript(*c, **kwargs):

469

"""HTML noscript element for no-script fallback."""

470

471

def Template(*c, **kwargs):

472

"""HTML template element for client-side templates."""

473

474

def Slot(*c, **kwargs):

475

"""HTML slot element for web components."""

476

477

# Mathematical elements

478

def Math(*c, **kwargs):

479

"""HTML math element for mathematical notation."""

480

```

481

482

### Utility Functions

483

484

Helper functions for HTML processing, syntax highlighting, and debugging.

485

486

```python { .api }

487

def highlight(s, lang='xml'):

488

"""

489

Syntax highlight code string.

490

491

Applies syntax highlighting to code strings for display

492

in HTML or terminal environments.

493

494

Parameters:

495

- s: str, code to highlight

496

- lang: str, language for syntax highlighting

497

498

Returns:

499

str: Highlighted code (HTML or ANSI codes)

500

"""

501

502

def showtags(s):

503

"""

504

Display HTML tags in string for debugging.

505

506

Visualizes HTML structure by showing tag boundaries

507

and nesting levels for debugging HTML generation.

508

509

Parameters:

510

- s: str, HTML string to analyze

511

512

Returns:

513

str: Formatted representation showing tag structure

514

"""

515

```

516

517

## Usage Examples

518

519

### Basic HTML Generation

520

521

```python

522

from fastcore.xml import ft, Html, Head, Title, Body, Div, P, A

523

524

# Simple element creation

525

div = ft('div', 'Hello World', class_='greeting')

526

print(to_xml(div))

527

# <div class="greeting">Hello World</div>

528

529

# Using convenience classes

530

paragraph = P('This is a paragraph with ', Strong('bold text'), '.')

531

print(to_xml(paragraph))

532

# <p>This is a paragraph with <strong>bold text</strong>.</p>

533

534

# Chaining methods for fluent API

535

container = (Div()

536

.set('Welcome to our site!')

537

.set(class_='container', id='main')

538

.set(P('This is the main content area.'))

539

)

540

541

print(to_xml(container))

542

# <div class="container" id="main">Welcome to our site!<p>This is the main content area.</p></div>

543

```

544

545

### Complete HTML Documents

546

547

```python

548

from fastcore.xml import *

549

550

# Build complete HTML document

551

def create_webpage(title_text, content):

552

return Html(

553

Head(

554

Title(title_text),

555

Meta(charset='utf-8'),

556

Meta(name='viewport', content='width=device-width, initial-scale=1'),

557

Link(rel='stylesheet', href='styles.css')

558

),

559

Body(

560

Header(

561

H1(title_text),

562

Nav(

563

Ul(

564

Li(A('Home', href='/')),

565

Li(A('About', href='/about')),

566

Li(A('Contact', href='/contact'))

567

)

568

)

569

),

570

Main(

571

Section(content, class_='content'),

572

Aside(

573

H2('Sidebar'),

574

P('This is sidebar content.')

575

)

576

),

577

Footer(

578

P('© 2024 My Website. All rights reserved.')

579

)

580

),

581

lang='en'

582

)

583

584

# Generate the page

585

webpage = create_webpage('My Website', [

586

H2('Welcome'),

587

P('This is the main content of the page.'),

588

P('You can add more paragraphs and elements here.')

589

])

590

591

html_string = to_xml(webpage)

592

print(html_string)

593

```

594

595

### Dynamic Content and Attributes

596

597

```python

598

from fastcore.xml import *

599

600

# Dynamic attribute handling

601

def create_button(text, button_type='button', **kwargs):

602

classes = ['btn']

603

if 'primary' in kwargs:

604

classes.append('btn-primary')

605

if 'large' in kwargs:

606

classes.append('btn-lg')

607

608

return Button(text,

609

type=button_type,

610

class_=classes, # List automatically joined with spaces

611

**{k: v for k, v in kwargs.items()

612

if k not in ['primary', 'large']})

613

614

# Create various buttons

615

submit_btn = create_button('Submit', 'submit', primary=True, id='submit-form')

616

cancel_btn = create_button('Cancel', onclick='closeModal()', large=True)

617

618

print(to_xml(submit_btn))

619

# <button type="submit" class="btn btn-primary" id="submit-form">Submit</button>

620

621

# CSS-style attributes from dictionaries

622

styled_div = Div('Styled content',

623

style={'color': 'red', 'background': 'yellow', 'padding': '10px'}

624

)

625

print(to_xml(styled_div))

626

# <div style="color:red; background:yellow; padding:10px">Styled content</div>

627

628

# Safe HTML content

629

from fastcore.xml import Safe

630

631

# This HTML won't be escaped

632

safe_content = Safe('<em>Emphasized</em> and <strong>bold</strong> text')

633

container = Div('This contains ', safe_content, '!')

634

print(to_xml(container))

635

# <div>This contains <em>Emphasized</em> and <strong>bold</strong> text!</div>

636

```

637

638

### Forms and Interactive Elements

639

640

```python

641

from fastcore.xml import *

642

643

# Complex form generation

644

def create_contact_form():

645

return Form(

646

Fieldset(

647

Legend('Contact Information'),

648

Div(

649

Label('Name:', fr='name'), # fr becomes 'for'

650

Input(type='text', id='name', name='name', required=True),

651

class_='form-group'

652

),

653

Div(

654

Label('Email:', fr='email'),

655

Input(type='email', id='email', name='email', required=True),

656

class_='form-group'

657

),

658

Div(

659

Label('Message:', fr='message'),

660

Textarea('', id='message', name='message', rows=5, cols=50),

661

class_='form-group'

662

)

663

),

664

Fieldset(

665

Legend('Preferences'),

666

Div(

667

Input(type='checkbox', id='newsletter', name='newsletter', value='yes'),

668

Label('Subscribe to newsletter', fr='newsletter'),

669

class_='checkbox-group'

670

),

671

Div(

672

Label('Preferred contact method:', fr='contact-method'),

673

Select(

674

Option('Email', value='email', selected=True),

675

Option('Phone', value='phone'),

676

Option('Text', value='text'),

677

id='contact-method',

678

name='contact_method'

679

),

680

class_='form-group'

681

)

682

),

683

Div(

684

Button('Submit', type='submit', class_='btn btn-primary'),

685

Button('Reset', type='reset', class_='btn btn-secondary'),

686

class_='form-actions'

687

),

688

method='POST',

689

action='/contact'

690

)

691

692

contact_form = create_contact_form()

693

print(to_xml(contact_form))

694

```

695

696

### Tables and Data Display

697

698

```python

699

from fastcore.xml import *

700

701

# Generate data table

702

def create_data_table(headers, rows):

703

return Table(

704

Caption('Data Summary'),

705

Thead(

706

Tr(*[Th(header) for header in headers])

707

),

708

Tbody(*[

709

Tr(*[Td(cell) for cell in row])

710

for row in rows

711

]),

712

class_='data-table'

713

)

714

715

# Sample data

716

headers = ['Name', 'Age', 'City', 'Score']

717

data = [

718

['Alice', 30, 'New York', 95],

719

['Bob', 25, 'San Francisco', 87],

720

['Charlie', 35, 'Chicago', 92]

721

]

722

723

table = create_data_table(headers, data)

724

725

# Add zebra striping and responsive classes

726

table = table.set(class_='data-table table-striped table-responsive')

727

728

print(to_xml(table))

729

```

730

731

### Component-Based HTML Generation

732

733

```python

734

from fastcore.xml import *

735

736

# Reusable components

737

class HTMLComponent:

738

"""Base class for reusable HTML components."""

739

740

def render(self):

741

raise NotImplementedError

742

743

class Card(HTMLComponent):

744

def __init__(self, title, content, image_url=None, actions=None):

745

self.title = title

746

self.content = content

747

self.image_url = image_url

748

self.actions = actions or []

749

750

def render(self):

751

card_content = []

752

753

if self.image_url:

754

card_content.append(

755

Img(src=self.image_url, class_='card-img-top', alt=self.title)

756

)

757

758

body_content = [

759

H5(self.title, class_='card-title'),

760

P(self.content, class_='card-text')

761

]

762

763

if self.actions:

764

body_content.append(

765

Div(*self.actions, class_='card-actions')

766

)

767

768

card_content.append(

769

Div(*body_content, class_='card-body')

770

)

771

772

return Div(*card_content, class_='card')

773

774

class CardGrid(HTMLComponent):

775

def __init__(self, cards, columns=3):

776

self.cards = cards

777

self.columns = columns

778

779

def render(self):

780

return Div(

781

*[card.render() for card in self.cards],

782

class_=f'card-grid cols-{self.columns}'

783

)

784

785

# Use components

786

cards = [

787

Card(

788

'Product 1',

789

'Description of product 1',

790

image_url='/images/product1.jpg',

791

actions=[

792

Button('Buy Now', class_='btn btn-primary'),

793

A('Learn More', href='/product1', class_='btn btn-secondary')

794

]

795

),

796

Card(

797

'Product 2',

798

'Description of product 2',

799

actions=[Button('Buy Now', class_='btn btn-primary')]

800

),

801

Card(

802

'Product 3',

803

'Description of product 3',

804

image_url='/images/product3.jpg'

805

)

806

]

807

808

grid = CardGrid(cards, columns=3)

809

html_output = to_xml(grid.render())

810

```

811

812

### Event System and Dynamic Updates

813

814

```python

815

from fastcore.xml import *

816

817

# Event-driven HTML updates

818

class LiveCounter:

819

def __init__(self, initial_value=0):

820

self.value = initial_value

821

self.display = Span(str(self.value), class_='counter-value')

822

self.container = Div(

823

P('Current count: ', self.display),

824

Button('Increment', onclick='increment()'),

825

Button('Decrement', onclick='decrement()'),

826

class_='counter-widget'

827

)

828

829

# Add event listener for updates

830

self.display.on(self.on_update)

831

832

def increment(self):

833

self.value += 1

834

self.display.set(str(self.value))

835

836

def decrement(self):

837

self.value -= 1

838

self.display.set(str(self.value))

839

840

def on_update(self, element):

841

print(f"Counter updated to: {self.value}")

842

843

def render(self):

844

return self.container

845

846

# Create and use counter

847

counter = LiveCounter(5)

848

counter.increment() # Triggers update event

849

html = to_xml(counter.render())

850

851

# Template system with placeholders

852

class Template:

853

def __init__(self, html_structure):

854

self.structure = html_structure

855

self.placeholders = {}

856

857

def set_placeholder(self, name, content):

858

self.placeholders[name] = content

859

return self

860

861

def render(self):

862

def replace_placeholders(element):

863

if hasattr(element, 'children'):

864

new_children = []

865

for child in element.children:

866

if isinstance(child, str) and child.startswith('{{') and child.endswith('}}'):

867

placeholder_name = child[2:-2].strip()

868

new_children.append(self.placeholders.get(placeholder_name, child))

869

else:

870

new_children.append(replace_placeholders(child) if hasattr(child, 'children') else child)

871

return element.set(*new_children)

872

return element

873

874

return replace_placeholders(self.structure)

875

876

# Use template

877

template = Template(

878

Div(

879

H1('{{title}}'),

880

P('{{description}}'),

881

Div('{{content}}', class_='main-content')

882

)

883

)

884

885

rendered = template.set_placeholder('title', 'Welcome') .set_placeholder('description', 'This is a dynamic page') .set_placeholder('content', 'Main page content here') .render()

886

887

print(to_xml(rendered))

888

```