Skip to content

Components

Overview

We supply some pre-designed that components can be used to help simplify development.


View To Component

Convert any Django view into a ReactPy component by using this decorator. Compatible with Function Based Views and Class Based Views. Views can be sync or async.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.http import HttpResponse
from reactpy import component, html
from reactpy_django.components import view_to_component


@view_to_component
def hello_world_view(request):
    return HttpResponse("Hello World!")


@component
def my_component():
    return html.div(
        hello_world_view(),
    )
See Interface

Parameters

Name Type Description Default
view Callable | View The view function or class to convert. N/A
compatibility bool If True, the component will be rendered in an iframe. When using compatibility mode tranforms, strict_parsing, request, args, and kwargs arguments will be ignored. False
transforms Sequence[Callable[[VdomDict], Any]] A list of functions that transforms the newly generated VDOM. The functions will be called on each VDOM node. tuple
strict_parsing bool If True, an exception will be generated if the HTML does not perfectly adhere to HTML5. True

Returns

Type Description
_ViewComponentConstructor A function that takes request, *args, key, **kwargs and returns a ReactPy component. All parameters are directly provided to your view, besides key which is used by ReactPy.
Potential information exposure when using compatibility = True

When using compatibility mode, ReactPy automatically exposes a URL to your view.

It is your responsibility to ensure privileged information is not leaked via this method.

You must implement a method to ensure only authorized users can access your view. This can be done via directly writing conditionals into your view, or by adding decorators such as user_passes_test to your views. For example...

1
2
3
4
5
6
7
8
from django.contrib.auth.decorators import user_passes_test
from reactpy_django.components import view_to_component


@view_to_component(compatibility=True)
@user_passes_test(lambda u: u.is_superuser)  # type: ignore[union-attr]
def example_view(request):
    ...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.contrib.auth.decorators import user_passes_test
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
from reactpy_django.components import view_to_component


@view_to_component(compatibility=True)
@method_decorator(user_passes_test(lambda u: u.is_superuser), name="dispatch")  # type: ignore[union-attr]
class ExampleView(TemplateView):
    ...
Existing limitations

There are currently several limitations of using view_to_component that may be resolved in a future version.

  • Requires manual intervention to change request methods beyond GET.
  • ReactPy events cannot conveniently be attached to converted view HTML.
  • Has no option to automatically intercept local anchor link (such as <a href='example/'></a>) click events.

Please note these limitations do not exist when using compatibility mode.

How do I use this for Class Based Views?

You can simply pass your Class Based View directly into view_to_component.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from django.http import HttpResponse
from django.views import View
from reactpy import component, html
from reactpy_django.components import view_to_component


class HelloWorldView(View):
    def get(self, request):
        return HttpResponse("Hello World!")


vtc = view_to_component(HelloWorldView)


@component
def my_component():
    return html.div(
        vtc(),
    )
How do I transform views from external libraries?

In order to convert external views, you can utilize view_to_component as a function, rather than a decorator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from example.views import example_view
from reactpy import component, html
from reactpy_django.components import view_to_component

example_vtc = view_to_component(example_view)


@component
def my_component():
    return html.div(
        example_vtc(),
    )
How do I provide request, args, and kwargs to a view?

Request

You can use the request parameter to provide the view a custom request object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from django.http import HttpRequest, HttpResponse
from reactpy import component, html
from reactpy_django.components import view_to_component

example_request = HttpRequest()
example_request.method = "PUT"


@view_to_component
def hello_world_view(request):
    return HttpResponse(f"Hello World! {request.method}")


@component
def my_component():
    return html.div(
        hello_world_view(
            example_request,
        ),
    )

args and kwargs

You can use the args and kwargs parameters to provide positional and keyworded arguments to a view.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from django.http import HttpResponse
from reactpy import component, html
from reactpy_django.components import view_to_component


@view_to_component
def hello_world_view(request, arg1, arg2, key1=None, key2=None):
    return HttpResponse(f"Hello World! {arg1} {arg2} {key1} {key2}")


@component
def my_component():
    return html.div(
        hello_world_view(
            None,  # Your request object (optional)
            "value_1",
            "value_2",
            key1="abc",
            key2="123",
        ),
    )
How do I use strict_parsing, compatibility, and transforms?

strict_parsing

By default, an exception will be generated if your view's HTML does not perfectly adhere to HTML5.

However, there are some circumstances where you may not have control over the original HTML, so you may be unable to fix it. Or you may be relying on non-standard HTML tags such as <my-tag> Hello World </my-tag>.

In these scenarios, you may want to rely on best-fit parsing by setting the strict_parsing parameter to False.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.http import HttpResponse
from reactpy import component, html
from reactpy_django.components import view_to_component


@view_to_component(strict_parsing=False)
def hello_world_view(request):
    return HttpResponse("<my-tag> Hello World </my-tag>")


@component
def my_component():
    return html.div(
        hello_world_view(),
    )

Note: Best-fit parsing is designed to be similar to how web browsers would handle non-standard or broken HTML.


compatibility

For views that rely on HTTP responses other than GET (such as PUT, POST, PATCH, etc), you should consider using compatibility mode to render your view within an iframe.

Any view can be rendered within compatibility mode. However, the transforms, strict_parsing, request, args, and kwargs arguments do not apply to compatibility mode.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.http import HttpResponse
from reactpy import component, html
from reactpy_django.components import view_to_component


@view_to_component(compatibility=True)
def hello_world_view(request):
    return HttpResponse("Hello World!")


@component
def my_component():
    return html.div(
        hello_world_view(),
    )

Note: By default the compatibility iframe is unstyled, and thus won't look pretty until you add some CSS.


transforms

After your view has been turned into VDOM (python dictionaries), view_to_component will call your transforms functions on every VDOM node.

This allows you to modify your view prior to rendering.

For example, if you are trying to modify the text of a node with a certain id, you can create a transform like such:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from django.http import HttpResponse
from reactpy import component, html
from reactpy_django.components import view_to_component


def example_transform(vdom):
    attributes = vdom.get("attributes")
    if attributes and attributes.get("id") == "hello-world":
        vdom["children"][0] = "Good Bye World!"


@view_to_component(transforms=[example_transform])
def hello_world_view(request):
    return HttpResponse("<div id='hello-world'> Hello World! <div>")


@component
def my_component():
    return html.div(
        hello_world_view(),
    )

Django CSS

Allows you to defer loading a CSS stylesheet until a component begins rendering. This stylesheet must be stored within Django's static files.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from reactpy import component, html
from reactpy_django.components import django_css


@component
def my_component():
    return html.div(
        django_css("css/buttons.css"),
        html.button("My Button!"),
    )
See Interface

Parameters

Name Type Description Default
static_path str The path to the static file. This path is identical to what you would use on a static template tag. N/A
key Key | None A key to uniquely identify this component which is unique amongst a component's immediate siblings None

Returns

Type Description
Component A ReactPy component.
Should I put django_css at the top of my HTML?

Yes, if the stylesheet contains styling for your component.

Can I load static CSS using html.link instead?

While you can load stylesheets with html.link, keep in mind that loading this way does not ensure load order. Thus, your stylesheet will be loaded after your component is displayed. This would likely cause unintended visual behavior, so use this at your own discretion.

Here's an example on what you should avoid doing for Django static files:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.templatetags.static import static
from reactpy import component, html


@component
def my_component():
    return html.div(
        html.link({"rel": "stylesheet", "href": static("css/buttons.css")}),
        html.button("My Button!"),
    )
How do I load external CSS?

django_css can only be used with local static files.

For external CSS, substitute django_css with html.link.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from reactpy import component, html


@component
def my_component():
    return html.div(
        html.link(
            {"rel": "stylesheet", "href": "https://example.com/external-styles.css"}
        ),
        html.button("My Button!"),
    )
Why not load my CSS in <head>?

Traditionally, stylesheets are loaded in your <head> using the {% load static %} template tag.

To help improve webpage load times, you can use the django_css component to defer loading your stylesheet until it is needed.

Django JS

Allows you to defer loading JavaScript until a component begins rendering. This JavaScript must be stored within Django's static files.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from reactpy import component, html
from reactpy_django.components import django_js


@component
def my_component():
    return html.div(
        html.button("My Button!"),
        django_js("js/scripts.js"),
    )
See Interface

Parameters

Name Type Description Default
static_path str The path to the static file. This path is identical to what you would use on a static template tag. N/A
key Key | None A key to uniquely identify this component which is unique amongst a component's immediate siblings None

Returns

Type Description
Component A ReactPy component.
Should I put django_js at the bottom of my HTML?

Yes, if your scripts are reliant on the contents of the component.

Can I load static JavaScript using html.script instead?

While you can load JavaScript with html.script, keep in mind that loading this way does not ensure load order. Thus, your JavaScript will likely be loaded at an arbitrary time after your component is displayed.

Here's an example on what you should avoid doing for Django static files:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.templatetags.static import static
from reactpy import component, html


@component
def my_component():
    return html.div(
        html.script({"src": static("js/scripts.js")}),
        html.button("My Button!"),
    )
How do I load external JS?

django_js can only be used with local static files.

For external JavaScript, substitute django_js with html.script.

1
2
3
4
5
6
7
8
9
from reactpy import component, html


@component
def my_component():
    return html.div(
        html.script({"src": "https://example.com/external-scripts.js"}),
        html.button("My Button!"),
    )
Why not load my JS in <head>?

Traditionally, JavaScript is loaded in your <head> using the {% load static %} template tag.

To help improve webpage load times, you can use the django_js component to defer loading your JavaScript until it is needed.


Last update: September 7, 2023
Authors: Mark Bakhit