How to build user interface or component using ReactPy

user interface and components in reactpy
Updated: July 29, 2023

A. Introduction

User interfaces or components are basically just the elements of an HTML. An element is consisted of three parts, a start tag, a content and an end tag. An element may also contain an attribute to enhance it.

Here is an example of an HTML element.

<h3 style="color: red;">ReactPy</h3>

The h3 is the tag. This element has a ReactPy content. It also has a style attribute which is comprised of property name color and property value red responsible for turning the text color to red.

This is the result after rendering that element.
rendered user interface
The text color had changed to red.

Here is an example of a button element that has an onclick event attribute.

<button type="button" onclick="alert('Hello world!')">Click Me!</button>

In its basic form, ReactPy component is just an html element wrapped in a function with component decorator.

@component
def BasicComponent():
    return html.h3('ReactPy')

In section C, we will be generating some ReactPy components from sample application. Importing component from other module is also covered.

B. Different kinds of tags

HTML has more than 100 tags. This includes but is not limited to <html>, <body>, <h1>, <img>, <a>, <head>, <div>, and others.

Below is a simple example demonstrating the utilization of tags in an HTML page.

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Title of the article</title>
</head>
<body>

<h1>A header tag with size 1</h1>
<p>A paragraph tag.</p>

</body>
</html>

The element with title is a component in React and ReactPy. The element with head is also a component that is composed of an element with title. The head is the parent component of title and the title is the child of head.

The element with tag body has 2 children. They are the header <h1> and paragraph <p>.

C. Creating component with ReactPy

Component is created with a Python function decorated with a component. Components should be designed so that it can be reused in other applications.

1. Sample components and usage

Let us create a Title, TitleDescription, and Home components. We will call them at certain location in our code and render a page.

@component
def Title():
    return html.h1("Create component using ReactPy")

@component
def TitleDescription():
    return html.p("ReactPy component can be created by composing \
                  a function that will return an html element.")

Our root component Home. It just calls other components.

@component
def Home():
    return html.div(
        Title(),
        TitleDescription()
    )

Here is the full code along with some imports and entry point. Note we use the fastapi backend.

title.py
from reactpy import component, html
from reactpy.backend.fastapi import configure
from fastapi import FastAPI

@component
def Title():
    return html.h1("Create component using ReactPy")

@component
def TitleDescription():
    return html.p("ReactPy component can be created by composing \
                  a function that will return an html element.")

@component
def Home():
    return html.div(
        Title(),
        TitleDescription(),
    )

app = FastAPI()
configure(app, Home)

We can run this code with the following command line.

uvicorn title:app

Be sure you have already installed python and ReactPy or read the guide on how to install reactpy.

Typical console output.

INFO:     Will watch for changes in these directories: ['C:\\myreactpyproject']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [9540] using WatchFiles
INFO:     Started server process [11640]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     ('127.0.0.1', 53348) - "WebSocket /_reactpy/stream" [accepted]
INFO:     connection open

Open your web browser such as google chrome and paste http://127.0.0.1:8000 in the address bar.

The output would look like this.
create component with reactpy

a. Improve code for Reusability

We can improve the existing code by adding parameters for Title() and TitleDescription() to make it more reusable. Our latest title.py module is this.

title.py
from reactpy import component, html
from reactpy.backend.fastapi import configure
from fastapi import FastAPI

@component
def Title(title):
    return html.h1(title)

@component
def TitleDescription(description):
    return html.p(description)

@component
def Home():
    title = "Create component using ReactPy"
    description = "ReactPy component can be created by composing \
                   a function that will return an html element."

    return html.div(
        Title(title),
        TitleDescription(description),
    )

app = FastAPI()
configure(app, Home)

The component Title and TitleDescription have now a title and a description parameters respectively.

By modifying the title and description values, the revision would permit the utilization of Title and TitleDescription components in other modules through imports.

b. Importing component from other module

Here is a case, use the Title component from title.py file or module into the todo.py module in Todo application. Note this is not a realistic Todo App, it is just a demo to demonstrate importing component.

todo.py
from reactpy import component, html
from reactpy.backend.fastapi import configure
from fastapi import FastAPI
from title import Title  # this one

@component
def Todo():
    todo_title = "Todo Application"

    return html.div(
        Title(todo_title),  # imported from title.py module

        html.ol(
            html.li('Study React'),
            html.li('Study ReactPy'),
        )
    )

app = FastAPI()
configure(app, Todo)

This is the result after executing the command.

uvicorn todo:app
todo application

So we got the todo_title displayed using the Title component from title.py module.

2. Random number generator

Let us build a simple random number generator web application. The user will press the button and random number will be printed. This also features how to define a function that triggers after pressing the button and how to manage a variable using use_state() hook.

randomnumber.py
import random
from reactpy import component, html, hooks
from reactpy.backend.fastapi import configure
from fastapi import FastAPI

RANDOM_NUMBER_INIT_VALUE = 0
BUTTON_TEXT = 'Generate Random Number'
MIN_NUM = 0
MAX_NUM = 1000

@component
def RandomNumbers():
    random_number, set_random_number = hooks.use_state(RANDOM_NUMBER_INIT_VALUE)

    def generate_random_number(event):
        # Update the value of the random_number variable.
        set_random_number(random.randint(MIN_NUM, MAX_NUM))

    return html.div(
        html.button({'on_click': generate_random_number}, BUTTON_TEXT),

        # Display the random number.
        html.p(f'random number is {random_number}')
    )

app = FastAPI()
configure(app, RandomNumbers)

Run the application.

uvicorn randomnumber:app

You will get something like this after pressing the button.

random number generator

We can apply styling on the div tag so that the button and text will be centered on the page.

return html.div(
        {'style': {'text-align': 'center'}},  # this line
        html.button({'on_click': generate_random_number}, BUTTON_TEXT),

        # Display the random number.
        html.p(f'random number is {random_number}')
    )

3. BMI (Body Mass Index) Application

This application features the input and button components as well as use_state() hook. User will enter the height in meters and weight in kilograms. BMI is calculated after the button is pressed.

bmi.py
from reactpy import component, html, hooks
from reactpy.backend.fastapi import configure
from fastapi import FastAPI

@component
def BMI():
    height, set_height = hooks.use_state('')
    weight, set_weight = hooks.use_state('')
    bmi, set_bmi = hooks.use_state(0)

    def get_bmi(event):
        if height == '' or weight == '':
            return
        cal_bmi = float(weight) / (float(height) * float(height))
        set_bmi(cal_bmi)

    return html.div(
        {'style': {'display': 'flex', 'flex-direction': 'column',
                   'align-items': 'center'}},

        html.p('Height in meters '),
        html.input(
            {
                'type': 'text',
                'placeholder': 'enter height in meters',
                'on_change': lambda event:set_height(event['target']['value'])
             }
        ),

        html.p('Weight in kg '),
        html.input(
            {
                'type': 'text',
                'placeholder': 'enter weight in kg',
                'on_change': lambda event:set_weight(event['target']['value'])
            }
        ),

        html.p(),
        html.button({'on_click': get_bmi}, 'Calculate BMI'),

        html.h3(f'BMI: {round(bmi, 2)}')
    )

app = FastAPI()
configure(app, BMI)

Run the application.

uvicorn bmi:app

This is how it would appear.

bmi application

Please take a look at the reference section regarding hooks and bmi calculation.

D. Summary

Creating components as user interfaces begins after understanding the structure of HTML elements. Some example applications are presented to see how ReactPy components are created including the use of use_state() hook. We also see how to import a component from other module.

E. References