The fastest way to create HTML apps - a next-generation Python web framework for building fast, scalable web applications with minimal code
—
Integration with popular JavaScript libraries including Markdown rendering, syntax highlighting, interactive components, and client-side scripting utilities.
Pre-configured JavaScript library loaders for popular front-end libraries.
def MarkdownJS(*c, **kw):
"""
Markdown parsing and rendering.
Integrates markdown-it library for client-side markdown
parsing and HTML rendering.
Args:
*c: Content or configuration
**kw: Library configuration options
Returns:
Script elements for markdown functionality
"""
def KatexMarkdownJS(*c, **kw):
"""
Markdown with KaTeX math support.
Combines markdown parsing with KaTeX for mathematical
formula rendering in markdown content.
Args:
*c: Content or configuration
**kw: Library and math rendering options
Returns:
Script elements for markdown with math support
"""
def HighlightJS(*c, **kw):
"""
Syntax highlighting.
Integrates highlight.js for syntax highlighting
of code blocks in various programming languages.
Args:
*c: Configuration or language specifications
**kw: Highlighting options and themes
Returns:
Script and style elements for syntax highlighting
"""
def SortableJS(*c, **kw):
"""
Drag-and-drop sorting.
Integrates SortableJS for drag-and-drop functionality
on lists and grid elements.
Args:
*c: Configuration options
**kw: Sortable behavior settings
Returns:
Script elements for drag-and-drop functionality
"""
def MermaidJS(*c, **kw):
"""
Diagram and flowchart rendering.
Integrates Mermaid.js for rendering diagrams,
flowcharts, and other visualizations from text.
Args:
*c: Diagram definitions or configuration
**kw: Rendering options and themes
Returns:
Script elements for diagram rendering
"""Enhanced JavaScript execution and client-side scripting capabilities.
def Surreal(*c, **kw):
"""
Surreal JavaScript code block.
Creates Surreal.js code blocks for enhanced DOM
manipulation and client-side interactions.
Args:
*c: Surreal.js code content
**kw: Script attributes and options
Returns:
Script element with Surreal.js code
"""
def On(*c, **kw):
"""
Event handler JavaScript.
Creates JavaScript event handlers with simplified
syntax for DOM events.
Args:
*c: Event handler code
**kw: Event options and attributes
Returns:
JavaScript code for event handling
"""
def Prev(*c, **kw):
"""
Previous element event handler.
Creates event handlers that target the previous
sibling element in the DOM.
Args:
*c: Handler code
**kw: Event configuration
Returns:
JavaScript code for previous element targeting
"""
def Now(*c, **kw):
"""
Immediate JavaScript execution.
Executes JavaScript code immediately when the
element is rendered.
Args:
*c: JavaScript code to execute
**kw: Execution options
Returns:
Script element with immediate execution
"""
def AnyNow(*c, **kw):
"""
JavaScript execution on any element.
Executes JavaScript code on any matching element
when rendered or modified.
Args:
*c: JavaScript code
**kw: Element selection and execution options
Returns:
Script element with flexible execution
"""
def run_js(code: str):
"""
Execute JavaScript code.
Executes JavaScript code in the browser context
with proper error handling.
Args:
code: JavaScript code to execute
Returns:
Script element with code execution
"""Utility for loading JavaScript libraries from CDN services.
def jsd(library: str, version: str = None, **kwargs):
"""
JavaScript library loader from CDN.
Loads JavaScript libraries from jsDelivr CDN with
version management and dependency handling.
Args:
library: Library name (e.g., 'jquery', 'lodash')
version: Specific version to load (latest if None)
**kwargs: Additional loading options
Returns:
Script element with CDN library loading
"""Surreal.js integration for DOM manipulation and event handling without traditional JavaScript syntax.
def Surreal(code: str):
"""
Wrap JavaScript code in Surreal.js domReadyExecute.
Args:
code: JavaScript code to execute when DOM is ready
Returns:
Script element with Surreal.js DOM ready wrapper
"""
def On(code: str, event='click', sel='', me=True):
"""
Event handler with Surreal.js syntax.
Args:
code: JavaScript code to execute on event
event: DOM event type (click, submit, etc.)
sel: CSS selector for target elements
me: Whether to include 'me' context
Returns:
Surreal.js event handler script
"""
def Prev(code: str, event='click'):
"""
Event handler on previous sibling element.
Args:
code: JavaScript code to execute
event: DOM event type
Returns:
Surreal.js previous sibling event handler
"""
def Now(code: str, sel=''):
"""
Execute JavaScript immediately on page load.
Args:
code: JavaScript code to execute
sel: CSS selector for context
Returns:
Immediate execution script
"""
def AnyNow(sel: str, code: str):
"""
Execute JavaScript on any selector match.
Args:
sel: CSS selector to match
code: JavaScript code to execute
Returns:
Conditional execution script
"""
def run_js(js: str, id=None, **kwargs):
"""
Execute JavaScript with automatic ID generation.
Args:
js: JavaScript code to run
id: Element ID (auto-generated if None)
**kwargs: Additional script attributes
Returns:
Script element with executable JavaScript
"""JavaScript utilities specifically designed for HTMX interactions.
def HtmxOn(eventname: str, code: str):
"""
HTMX event handler script generator.
Creates JavaScript event handlers that work
seamlessly with HTMX requests and responses.
Args:
eventname: HTMX event name (e.g., 'htmx:afterSwap')
code: JavaScript code to execute on event
Returns:
Script element with HTMX event handler
"""
def clear(id: str):
"""
Clear element content by ID.
Generates JavaScript to clear element content,
compatible with HTMX workflows.
Args:
id: Element ID to clear
Returns:
JavaScript code for clearing element content
"""Pre-defined JavaScript source URLs and code snippets.
htmxsrc: str
"""HTMX JavaScript source URL."""
fhjsscr: str
"""FastHTML JavaScript source code."""
surrsrc: str
"""Surreal.js JavaScript source URL."""
scopesrc: str
"""Scope JavaScript source code."""from fasthtml.common import *
app, rt = fast_app()
@rt('/markdown')
def markdown_demo():
return Titled("Markdown Rendering",
Container(
H1("Markdown with JavaScript"),
# Markdown input area
Div(
H2("Write Markdown"),
Textarea(
id="markdown-input",
placeholder="# Hello World\n\nType your **markdown** here...",
rows="10",
style="width: 100%; font-family: monospace;"
),
Button(
"Render Markdown",
onclick="renderMarkdown()",
cls="primary"
)
),
# Rendered output
Div(
H2("Rendered Output"),
Div(id="markdown-output", style="border: 1px solid #ccc; padding: 1rem; min-height: 200px;")
),
# Include Markdown.js
MarkdownJS(),
# Custom JavaScript for rendering
Script("""
function renderMarkdown() {
const input = document.getElementById('markdown-input').value;
const output = document.getElementById('markdown-output');
// Using markdown-it library
const md = window.markdownit();
const rendered = md.render(input);
output.innerHTML = rendered;
}
// Auto-render on load if there's content
document.addEventListener('DOMContentLoaded', function() {
const input = document.getElementById('markdown-input');
if (input.value.trim()) {
renderMarkdown();
}
});
""")
)
)
@rt('/markdown-math')
def markdown_math_demo():
return Titled("Markdown with Math",
Container(
H1("Markdown with KaTeX Math"),
# Sample content with math
Div(id="math-content", """
# Mathematical Expressions
Inline math: $E = mc^2$
Block math:
$$
\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}
$$
More complex equation:
$$
\\frac{1}{\\sqrt{2\\pi\\sigma^2}} e^{-\\frac{(x-\\mu)^2}{2\\sigma^2}}
$$
"""),
# Include Markdown.js with KaTeX
KatexMarkdownJS(),
Script("""
document.addEventListener('DOMContentLoaded', function() {
const content = document.getElementById('math-content');
const md = window.markdownit({
html: true,
typographer: true
});
// Render markdown with math
const rendered = md.render(content.textContent);
content.innerHTML = rendered;
// Render KaTeX math
renderMathInElement(content, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "$", right: "$", display: false}
]
});
});
""")
)
)from fasthtml.common import *
app, rt = fast_app()
@rt('/syntax-highlighting')
def syntax_demo():
return Titled("Syntax Highlighting",
Container(
H1("Code Syntax Highlighting"),
# Python code example
Div(
H2("Python Code"),
Pre(Code("""
def fibonacci(n):
\"\"\"Generate Fibonacci sequence up to n terms.\"\"\"
if n <= 0:
return []
elif n == 1:
return [0]
elif n == 2:
return [0, 1]
sequence = [0, 1]
for i in range(2, n):
sequence.append(sequence[i-1] + sequence[i-2])
return sequence
# Generate first 10 Fibonacci numbers
result = fibonacci(10)
print(f"First 10 Fibonacci numbers: {result}")
""", cls="language-python"))
),
# JavaScript code example
Div(
H2("JavaScript Code"),
Pre(Code("""
class Calculator {
constructor() {
this.result = 0;
}
add(value) {
this.result += value;
return this;
}
multiply(value) {
this.result *= value;
return this;
}
getValue() {
return this.result;
}
}
// Usage example
const calc = new Calculator();
const result = calc.add(5).multiply(3).add(2).getValue();
console.log(`Result: ${result}`); // Result: 17
""", cls="language-javascript"))
),
# SQL code example
Div(
H2("SQL Code"),
Pre(Code("""
-- Create users table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert sample data
INSERT INTO users (username, email) VALUES
('john_doe', 'john@example.com'),
('jane_smith', 'jane@example.com');
-- Query with join
SELECT u.username, u.email, p.title
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
WHERE u.created_at > '2024-01-01'
ORDER BY u.created_at DESC;
""", cls="language-sql"))
),
# Include Highlight.js
HighlightJS(),
# Initialize highlighting
Script("""
document.addEventListener('DOMContentLoaded', function() {
hljs.highlightAll();
});
""")
)
)from fasthtml.common import *
app, rt = fast_app()
@rt('/drag-drop')
def sortable_demo():
return Titled("Drag and Drop",
Container(
H1("Sortable Lists"),
# Simple sortable list
Div(
H2("Task List"),
Ul(
Li("Complete project proposal", id="task-1", cls="sortable-item"),
Li("Review code changes", id="task-2", cls="sortable-item"),
Li("Update documentation", id="task-3", cls="sortable-item"),
Li("Run test suite", id="task-4", cls="sortable-item"),
Li("Deploy to staging", id="task-5", cls="sortable-item"),
id="task-list",
style="list-style: none; padding: 0;"
),
P("Drag and drop to reorder tasks.")
),
# Sortable grid
Div(
H2("Image Gallery"),
Div(
*[Div(
Img(src=f"https://picsum.photos/150/150?random={i}", alt=f"Image {i}"),
P(f"Image {i}", style="text-align: center; margin: 0.5rem 0;"),
cls="gallery-item",
style="border: 1px solid #ddd; padding: 0.5rem; margin: 0.5rem;"
) for i in range(1, 9)],
id="image-gallery",
style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem;"
),
P("Drag images to rearrange the gallery.")
),
# Include SortableJS
SortableJS(),
# Initialize sortable functionality
Script("""
document.addEventListener('DOMContentLoaded', function() {
// Make task list sortable
const taskList = document.getElementById('task-list');
new Sortable(taskList, {
animation: 150,
ghostClass: 'sortable-ghost',
onEnd: function(evt) {
console.log('Task moved from', evt.oldIndex, 'to', evt.newIndex);
// Here you could send the new order to the server
}
});
// Make image gallery sortable
const gallery = document.getElementById('image-gallery');
new Sortable(gallery, {
animation: 150,
ghostClass: 'sortable-ghost',
onEnd: function(evt) {
console.log('Image moved from', evt.oldIndex, 'to', evt.newIndex);
}
});
});
"""),
# CSS for sortable items
Style("""
.sortable-item {
padding: 0.75rem;
margin: 0.25rem 0;
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
cursor: move;
transition: all 0.2s;
}
.sortable-item:hover {
background: #e9ecef;
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.sortable-ghost {
opacity: 0.4;
background: #007bff !important;
color: white;
}
.gallery-item {
cursor: move;
transition: transform 0.2s;
}
.gallery-item:hover {
transform: scale(1.05);
}
""")
)
)from fasthtml.common import *
app, rt = fast_app()
@rt('/diagrams')
def diagram_demo():
return Titled("Interactive Diagrams",
Container(
H1("Mermaid.js Diagrams"),
# Flowchart
Div(
H2("Process Flowchart"),
Div("""
graph TD
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Debug]
D --> E[Fix Issues]
E --> B
C --> F[Deploy]
F --> G[End]
""", cls="mermaid")
),
# Sequence diagram
Div(
H2("API Sequence Diagram"),
Div("""
sequenceDiagram
participant Client
participant API
participant Database
Client->>API: POST /users
API->>Database: INSERT user
Database-->>API: User created
API-->>Client: 201 Created
Client->>API: GET /users/123
API->>Database: SELECT user
Database-->>API: User data
API-->>Client: 200 OK
""", cls="mermaid")
),
# Gantt chart
Div(
H2("Project Timeline"),
Div("""
gantt
title Project Development Timeline
dateFormat YYYY-MM-DD
section Planning
Requirements :req, 2024-01-01, 2024-01-15
Design :design, after req, 10d
section Development
Backend :backend, 2024-01-20, 20d
Frontend :frontend, after design, 25d
section Testing
Unit Tests :test1, after backend, 5d
Integration :test2, after frontend, 10d
section Deployment
Staging :staging, after test2, 3d
Production :prod, after staging, 2d
""", cls="mermaid")
),
# Include Mermaid.js
MermaidJS(),
# Initialize Mermaid
Script("""
document.addEventListener('DOMContentLoaded', function() {
mermaid.initialize({
startOnLoad: true,
theme: 'default',
flowchart: {
useMaxWidth: true,
htmlLabels: true
}
});
});
""")
)
)from fasthtml.common import *
app, rt = fast_app(surreal=True)
@rt('/surreal-demo')
def surreal_demo():
return Titled("Surreal.js Demo",
Container(
H1("Client-Side Interactions"),
# DOM manipulation examples
Div(
H2("DOM Manipulation"),
Button("Change Text", id="change-text-btn"),
Button("Add Item", id="add-item-btn"),
Button("Toggle Visibility", id="toggle-btn"),
P("This text will change", id="dynamic-text"),
Ul(id="dynamic-list"),
Div("This div will toggle", id="toggle-div", style="margin-top: 1rem; padding: 1rem; background: #f0f0f0;")
),
# Form interactions
Div(
H2("Form Interactions"),
Input(type="text", id="name-input", placeholder="Enter your name"),
Button("Greet", id="greet-btn"),
P(id="greeting-output")
),
# Surreal.js code
Surreal("""
// DOM manipulation examples
$("#change-text-btn").on("click", () => {
$("#dynamic-text").text("Text changed at " + new Date().toLocaleTimeString());
});
$("#add-item-btn").on("click", () => {
const itemCount = $("#dynamic-list li").length + 1;
$("#dynamic-list").append(`<li>Item ${itemCount}</li>`);
});
$("#toggle-btn").on("click", () => {
$("#toggle-div").toggle();
});
// Form interactions
$("#greet-btn").on("click", () => {
const name = $("#name-input").value;
if (name) {
$("#greeting-output").text(`Hello, ${name}! Nice to meet you.`);
} else {
$("#greeting-output").text("Please enter your name first.");
}
});
// Real-time input feedback
$("#name-input").on("input", (e) => {
const value = e.target.value;
if (value.length > 0) {
$("#greet-btn").removeAttribute("disabled");
} else {
$("#greet-btn").setAttribute("disabled", "true");
}
});
""")
)
)from fasthtml.common import *
app, rt = fast_app()
@rt('/cdn-libraries')
def cdn_demo():
return Titled("CDN Library Integration",
Container(
H1("External Library Integration"),
# Chart.js example
Div(
H2("Chart Visualization"),
Canvas(id="chart-canvas", width="400", height="200"),
Button("Update Chart", id="update-chart-btn")
),
# Lodash utility example
Div(
H2("Data Processing"),
Pre(id="data-output", style="background: #f8f9fa; padding: 1rem; border-radius: 0.25rem;"),
Button("Process Data", id="process-data-btn")
),
# Load Chart.js from CDN
jsd("chart.js", "3.9.1"),
# Load Lodash from CDN
jsd("lodash", "4.17.21"),
# Custom JavaScript using loaded libraries
Script("""
document.addEventListener('DOMContentLoaded', function() {
// Chart.js example
const ctx = document.getElementById('chart-canvas').getContext('2d');
let chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: 'Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.5)',
'rgba(54, 162, 235, 0.5)',
'rgba(255, 205, 86, 0.5)',
'rgba(75, 192, 192, 0.5)',
'rgba(153, 102, 255, 0.5)',
'rgba(255, 159, 64, 0.5)'
]
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
});
// Update chart with random data
document.getElementById('update-chart-btn').addEventListener('click', function() {
chart.data.datasets[0].data = chart.data.datasets[0].data.map(() =>
Math.floor(Math.random() * 20) + 1
);
chart.update();
});
// Lodash example
document.getElementById('process-data-btn').addEventListener('click', function() {
const rawData = [
{ name: 'John', age: 30, city: 'New York' },
{ name: 'Jane', age: 25, city: 'San Francisco' },
{ name: 'Bob', age: 35, city: 'New York' },
{ name: 'Alice', age: 28, city: 'San Francisco' },
{ name: 'Charlie', age: 32, city: 'Chicago' }
];
// Use Lodash to process data
const groupedByCity = _.groupBy(rawData, 'city');
const avgAgeByCity = _.mapValues(groupedByCity, (people) =>
_.round(_.meanBy(people, 'age'), 1)
);
const sortedCities = _.sortBy(Object.keys(avgAgeByCity));
const result = {
'Total People': rawData.length,
'Cities': sortedCities,
'Average Age by City': avgAgeByCity,
'Oldest Person': _.maxBy(rawData, 'age'),
'Youngest Person': _.minBy(rawData, 'age')
};
document.getElementById('data-output').textContent =
JSON.stringify(result, null, 2);
});
});
""")
)
)Install with Tessl CLI
npx tessl i tessl/pypi-python-fasthtml