Skip to content

Your First Component

Overview

Components are one of the core concepts of ReactPy. They are the foundation upon which you build user interfaces (UI), which makes them the perfect place to start your ReactPy journey!

You will learn

  • What a component is
  • What role components play in a ReactPy application
  • How to write your first ReactPy component

Components: UI building blocks

On the Web, HTML lets us create rich structured documents with its built-in set of tags like <h1> and <li>:

<article>
    <h1>My First Component</h1>
    <ol>
        <li>Components: UI Building Blocks</li>
        <li>Defining a Component</li>
        <li>Using a Component</li>
    </ol>
</article>

This markup represents this article <article>, its heading <h1>, and an (abbreviated) table of contents as an ordered list <ol>. Markup like this, combined with CSS for style, and Python for interactivity, lies behind every sidebar, avatar, modal, dropdown—every piece of UI you see on the Web.

ReactPy lets you combine your markup, CSS, and Python into custom "components", reusable UI elements for your app. The table of contents code you saw above could be turned into a table_of_contents() component you could render on every page. Under the hood, it still uses the same HTML tags like html.article, html.h1, etc.

Just like with HTML tags, you can compose, order and nest components to design whole pages. For example, the documentation page you're reading is made out of ReactPy components:

html.div(
    html.header(
        search_bar(),
        html.a({"href": "/docs"}, "Docs"),
    ),
    sidebar(),
    html.main(
        table_of_contents(),
        documentation_text(),
    ),
)

As your project grows, you will notice that many of your designs can be composed by reusing components you already wrote, speeding up your development. Our table of contents above could be added to any screen with table_of_contents()! You can even jumpstart your project with components shared by the community.

Defining a component

Traditionally when creating web pages, web developers marked up their content and then added interaction by sprinkling on some JavaScript. This worked great when interaction was a nice-to-have on the web. Now it is expected for many sites and all apps. ReactPy puts interactivity first while still using the same technology: a ReactPy component is a Python function that you can sprinkle with markup. Here's what that looks like:

1
2
3
4
5
@component
def profile():
    return html.img(
        {"src": "https://i.imgur.com/MK3eW3Am.jpg", "alt": "Katherine Johnson"}
    )
1
2
3
img {
    height: 200px;
}
1
# TODO

And here's how to build a component:

Step 1: Import what you need

Every component needs the @component decorator and the html tag constructor:

from reactpy import component, html

Unlike ReactJS, there is no export statement. To use a component from another file you import it like any other Python object, which you will learn about in Importing and Exporting Components.

Step 2: Define the function

With def profile(): you define a Python function with the name profile. The @component decorator turns that function into something ReactPy can render.

Pitfall

ReactPy components are ordinary Python functions, so follow Python's naming conventions and write them in snake_case.

The ReactJS rule that "component names must start with a capital letter" does not apply. ReactJS needs that rule to tell components apart from HTML tags in its markup syntax. ReactPy has no markup syntax: HTML tags are reached through html. and components are called directly, so the difference is already unambiguous.

Step 3: Add markup

The component returns an html.img element with src and alt attributes. There is no JSX or PSX in ReactPy — a tag is a normal Python call whose first argument is a dictionary of attributes and whose remaining arguments are its children.

Return statements can be written all on one line when the element is short:

return html.h1("Amazing scientists")

For anything longer, wrap the element in parentheses rather than relying on a backslash continuation:

return html.img(
    {"src": "https://i.imgur.com/MK3eW3As.jpg", "alt": "Katherine Johnson"}
)

Using a component

Now that you've defined your profile component, you can nest it inside other components. For example, you can define a gallery component that uses multiple profile components:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@component
def profile():
    return html.img(
        {"src": "https://i.imgur.com/MK3eW3As.jpg", "alt": "Katherine Johnson"}
    )


@component
def gallery():
    return html.section(
        html.h1("Amazing scientists"),
        profile(),
        profile(),
        profile(),
    )
1
2
3
4
img {
    margin: 0 10px 10px 0;
    height: 90px;
}
1
# TODO

What the browser sees

Notice the difference in how the two kinds of calls are made:

  • html.section(...) and html.h1(...) are attributes on the html object, so ReactPy knows they are HTML tags.
  • profile() is a function you wrote and decorated with @component, so ReactPy knows it is a component.

And profile contains even more HTML: html.img. In the end, this is what the browser sees:

<section>
    <h1>Amazing scientists</h1>
    <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
    <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
    <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</section>

Nesting and organizing components

Components are regular Python functions, so you can keep multiple components in the same file. This is convenient when components are relatively small or tightly related to each other. If this file gets crowded, you can always move profile to a separate file. You will learn how to do this shortly on the page about imports.

Because the profile components are rendered inside gallery—even several times!—we can say that gallery is a parent component, rendering each profile as a "child". This is part of the magic of ReactPy: you can define a component once, and then use it in as many places and as many times as you like.

Pitfall

Components can render other components, but you must never nest their definitions:

from reactpy import component, html


# Do not do this: a component defined inside another component.
@component
def gallery():
    @component
    def profile():
        return html.img({"src": "https://i.imgur.com/MK3eW3As.jpg"})

    return html.section(
        html.h1("Amazing scientists"),
        profile(),
        profile(),
        profile(),
    )

Instead, define every component at the top level of your module:

@component
def profile():
    return html.img(
        {"src": "https://i.imgur.com/MK3eW3As.jpg", "alt": "Katherine Johnson"}
    )


@component
def gallery():
    return html.section(
        html.h1("Amazing scientists"),
        profile(),
        profile(),
        profile(),
    )

Here is why. When ReactPy re-renders gallery, it matches each child against the child from the previous render by the identity of its function. A component defined inside another function is a brand new function object every time the parent runs, so ReactPy concludes the old child is gone: it unmounts the previous profile, throws away its state and Effects, and mounts a fresh one. Rendering still looks correct, which makes this bug easy to miss and hard to trace.

When a child component needs some data from a parent, pass it by props instead of nesting definitions.

Deep Dive

Components all the way down

Your ReactPy application begins at a "root" component. This is the component you hand to an executor — for example the hello_world component passed to ReactPy in Creating a Standalone React App.

Most ReactPy apps use components all the way down. This means that you won't only use components for reusable pieces like buttons, but also for larger pieces like sidebars, lists, and ultimately, complete pages! Components are a handy way to organize UI code and markup, even if some of them are only used once.

Because your components run on the server, ReactPy can also render them into the initial HTML response instead of waiting for a browser to do the work. See Add React to an Existing Project to render components inside pages you already have.

Still, many websites only use ReactPy to add interactivity to existing HTML pages. They have many root components instead of a single one for the entire page. You can use as much—or as little—ReactPy as you need.

Recap

You've just gotten your first taste of ReactPy! Let's recap some key points.

  • ReactPy lets you create components, reusable UI elements for your app.
  • In a ReactPy app, every piece of UI is a component.
  • ReactPy components are regular Python functions except:

    1. They are decorated with @component.
    2. They return elements built with html.
  • Attributes are a dict, children are the remaining arguments, and both are ordinary Python — which means for loops, if statements, and variables work exactly as you would expect.

Next Steps

Check out Importing and Exporting Components to organize components across files, or jump straight to Passing Props to a Component to make yours configurable.

Authors: Archmonger