CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-reactpy

Reactive user interfaces with pure Python

Pending
Overview
Eval results
Files

widgets.mddocs/

Widgets and Utilities

Pre-built components and utility functions for common use cases and data manipulation. ReactPy provides ready-to-use widgets and helpful utilities to accelerate development.

Capabilities

Image Widget

Enhanced image component with automatic format detection:

def image(src: str, **attributes) -> VdomDict: ...

Parameters:

  • src: Image source URL or path
  • **attributes: Additional HTML attributes

Returns: VdomDict representing an img element with enhanced functionality

Usage Examples:

from reactpy.widgets import image

# Basic image
photo = image("https://example.com/photo.jpg")

# Image with attributes
styled_image = image(
    "logo.png",
    alt="Company Logo",
    width=200,
    className="logo"
)

# Responsive image
responsive = image(
    "hero.jpg",
    style={"maxWidth": "100%", "height": "auto"}
)

Linked Inputs

Create synchronized input components:

def linked_inputs(*inputs) -> list[VdomDict]: ...

Parameters:

  • *inputs: Input element configurations

Returns: List of synchronized input elements

Usage Examples:

from reactpy import component, html, use_state
from reactpy.widgets import linked_inputs

@component
def SynchronizedInputs():
    value, set_value = use_state("")
    
    # Create linked inputs that share the same value
    input1, input2, input3 = linked_inputs(
        {"placeholder": "Input 1", "value": value, "onChange": set_value},
        {"placeholder": "Input 2", "value": value, "onChange": set_value},
        {"placeholder": "Input 3", "value": value, "onChange": set_value}
    )
    
    return html.div(
        html.h3("Linked Inputs"),
        html.p("Type in any input to see synchronization:"),
        input1,
        input2,
        input3,
        html.p(f"Current value: {value}")
    )

Ref Utility Class

Mutable reference container that persists across renders:

class Ref[T]:
    current: T
    
    def __init__(self, initial_value: T = None): ...

Attributes:

  • current: The mutable value stored in the reference

Usage Examples:

from reactpy import component, html, use_ref, use_effect
from reactpy.utils import Ref

@component
def FocusableInput():
    input_ref = use_ref(None)
    click_count = use_ref(0)
    
    def handle_focus():
        if input_ref.current:
            input_ref.current.focus()
    
    def handle_click():
        click_count.current += 1
        print(f"Clicked {click_count.current} times")
    
    return html.div(
        html.input({"ref": input_ref, "placeholder": "I can be focused"}),
        html.button({"onClick": handle_focus}, "Focus Input"),
        html.button({"onClick": handle_click}, "Count Clicks")
    )

# Manual Ref creation
manual_ref = Ref("initial value")
manual_ref.current = "updated value"

Sample Application

Pre-built sample application demonstrating ReactPy features:

def SampleApp() -> VdomDict: ...

Returns: Complete sample application component

Usage Examples:

from reactpy import run
from reactpy.sample import SampleApp

# Run the sample application
run(SampleApp)

# Embed sample app in your own component
@component
def MyApp():
    return html.div(
        html.h1("My Application"),
        html.div({"style": {"border": "1px solid #ccc", "padding": "20px"}},
            SampleApp()
        )
    )

HTML/VDOM Conversion Utilities

Convert between HTML strings and VDOM structures:

def html_to_vdom(html_string: str) -> VdomDict: ...
def vdom_to_html(vdom_dict: VdomDict) -> str: ...

Usage Examples:

from reactpy.utils import html_to_vdom, vdom_to_html

# Convert HTML string to VDOM
html_str = """
<div class="container">
    <h1>Title</h1>
    <p>Content here</p>
    <button onclick="alert('clicked')">Click me</button>
</div>
"""

vdom_element = html_to_vdom(html_str)

# Convert VDOM back to HTML
html_output = vdom_to_html(vdom_element)
print(html_output)

# Use in components
@component
def HtmlContent():
    dynamic_html = "<p>This is <strong>dynamic</strong> content</p>"
    vdom_content = html_to_vdom(dynamic_html)
    
    return html.div(
        html.h2("Dynamic HTML Content"),
        vdom_content
    )

Utility Patterns

Common patterns using widgets and utilities:

@component
def FormWithValidation():
    form_data, set_form_data = use_state({
        "name": "",
        "email": "",
        "password": "",
        "confirm_password": ""
    })
    
    # Create linked password inputs for confirmation
    password_input, confirm_input = linked_inputs(
        {
            "type": "password",
            "placeholder": "Password",
            "value": form_data["password"],
            "onChange": lambda e: update_field("password", e["target"]["value"])
        },
        {
            "type": "password", 
            "placeholder": "Confirm Password",
            "value": form_data["confirm_password"],
            "onChange": lambda e: update_field("confirm_password", e["target"]["value"])
        }
    )
    
    def update_field(field, value):
        set_form_data({**form_data, field: value})
    
    def validate_form():
        return (
            form_data["name"] and
            form_data["email"] and
            form_data["password"] and
            form_data["password"] == form_data["confirm_password"]
        )
    
    return html.form(
        html.div(
            html.label("Name:"),
            html.input({
                "value": form_data["name"],
                "onChange": lambda e: update_field("name", e["target"]["value"])
            })
        ),
        html.div(
            html.label("Email:"),
            html.input({
                "type": "email",
                "value": form_data["email"],
                "onChange": lambda e: update_field("email", e["target"]["value"])
            })
        ),
        html.div(
            html.label("Password:"),
            password_input
        ),
        html.div(
            html.label("Confirm Password:"),
            confirm_input
        ),
        html.button(
            {
                "type": "submit",
                "disabled": not validate_form()
            },
            "Submit"
        )
    )

@component
def ImageGallery(images):
    return html.div(
        {"className": "gallery"},
        *[
            image(
                img_url,
                key=img_url,
                className="gallery-image",
                alt=f"Gallery image {i+1}",
                loading="lazy"
            )
            for i, img_url in enumerate(images)
        ]
    )

@component
def DynamicContent():
    html_content, set_html_content = use_state("")
    
    def load_content():
        # Simulate loading HTML from API
        new_html = """
        <div class="loaded-content">
            <h3>Loaded Content</h3>
            <p>This content was loaded dynamically!</p>
            <ul>
                <li>Item 1</li>
                <li>Item 2</li>
                <li>Item 3</li>
            </ul>
        </div>
        """
        set_html_content(new_html)
    
    return html.div(
        html.button({"onClick": load_content}, "Load Content"),
        html_to_vdom(html_content) if html_content else html.p("No content loaded")
    )

Custom Widget Creation

Create your own reusable widgets:

def card(*children, title=None, className="card"):
    """Custom card widget"""
    return html.div(
        {"className": className},
        html.h3(title) if title else None,
        html.div({"className": "card-body"}, *children)
    )

def button_group(*buttons, orientation="horizontal"):
    """Custom button group widget"""
    class_name = f"btn-group btn-group-{orientation}"
    return html.div(
        {"className": class_name, "role": "group"},
        *buttons
    )

def data_table(data, columns):
    """Custom data table widget"""
    return html.table(
        {"className": "data-table"},
        html.thead(
            html.tr(
                *[html.th(col["label"]) for col in columns]
            )
        ),
        html.tbody(
            *[
                html.tr(
                    *[html.td(str(row.get(col["key"], ""))) for col in columns],
                    key=f"row-{i}"
                )
                for i, row in enumerate(data)
            ]
        )
    )

# Usage of custom widgets
@component
def CustomWidgetExample():
    users = [
        {"id": 1, "name": "Alice", "email": "alice@example.com"},
        {"id": 2, "name": "Bob", "email": "bob@example.com"}
    ]
    
    columns = [
        {"key": "id", "label": "ID"},
        {"key": "name", "label": "Name"},
        {"key": "email", "label": "Email"}
    ]
    
    return html.div(
        card(
            data_table(users, columns),
            title="User List"
        ),
        button_group(
            html.button("Add User"),
            html.button("Edit User"),
            html.button("Delete User")
        )
    )

Install with Tessl CLI

npx tessl i tessl/pypi-reactpy

docs

backend.md

components.md

configuration.md

events.md

hooks.md

html-elements.md

index.md

svg-elements.md

testing.md

vdom.md

web-modules.md

widgets.md

tile.json