Skip to content

Syntax similar to JSX #918

Open

Description

@Archmonger

Current Situation

ReactJS has a method of HTML templating called JSX. We currently do not have an equivalent. We should create a Python-based JSX equivalent that operates similarly to how it is used in ReactJS (Javascript).

The key difference here is we will not use a dedicated file extension (such as .psx) in order to not break existing toolchains. Instead, we will rely on the tag string PEP that adds template literals to Python. Here is an example of the tag string syntax:

from reactpy import html

button_style = {"font_style": "bold"}
button_text = "Click me!"
view = html(t"<button on_click={lambda event: ...} style={button_text}>{button_text}</button>")

While we wait for the tag string PEP to be merged, we could potentially use an interim transpiler to use a similar syntax. The interim transpiler syntax would look something like this:

from reactpy import html

button_style = {"font_style": "bold"}
button_text = "Click me!"
view = html @ f"<button on_click={lambda event: ...} style={button_text}>{button_text}</button>"

Proposed Actions

Aid in the development of this proposed transpiler and then develop an html tag function. An initial implementation of an html tag can be found here.

News: There is now a VSCode Extension to add syntax highlighting for inline HTML. (and a second one)

Activity

  1. added
    priority-2-moderateShould be resolved on a reasonable timeline.
    and removed on Feb 9, 2023
  2. added this to the milestone on Feb 9, 2023
  3. removed this from the milestone on Feb 21, 2023
  4. bitnom commented on Feb 25, 2023

    @bitnom

    If a transpiler is required to get the same sort of syntax as JSX, then how would template literals be any better than fstrings?

  5. rmorshea commented on Feb 25, 2023

    @rmorshea
    Collaborator

    The main purpose of template literals is to have a dedicated syntax. Transpilers allow you to write any syntax you'd like in your Python files, and at least for JSX, that's already been done. The problem, and the reason I suspect Pyxl never saw wide adoption, is because it breaks all the tools you would normally use with a Python file (e.g. black, flake8, pylint, mypy, the list goes on...). You could as I proposed above, co-opt an existing syntax which is seen infrequently (e.g. tag @ f"..."), but without standardization, no one is going to create tooling that understands that bespoke syntax and provides highlighting and auto-completions.

  6. rmorshea commented on Apr 22, 2023

    @rmorshea
    Collaborator

    I've published an import-time transpiler that implements that aforementioned tag string spec.

    $ pip install tagstr
    
    # tagstr: on
    name = "world"
    print @ f"hello {name}!"
    hello  (<function <lambda> at 0x7f7a8586b920>, 'name', None, None) !
    

    I don't think this is ready for production yet, but with some more work behind this I think it provides a promising alternative to the current, and rather disjointed, patterns for constructing views in ReactPy. Integrating this into ReactPy could also act as a compelling real-world use case for the Tag String PEP itself.

  7. mtrunkbear commented on Jun 13, 2023

    @mtrunkbear

    That could be PSX python syntax extension, or PYX python XML

  8. mtrunkbear commented on Jun 13, 2023

    @mtrunkbear

    @rmorshea Very good work bro, i was reading the tag string docs and tutorial and i think that is a very useful aproximation.

  9. aranega commented on Jul 13, 2023

    @aranega

    Just for the sake of "state of the art", there is also this project named packed that is similar to pyxl3, but the syntax looks a little bit more like like tsx syntax on some small aspects. I guess the same criticisms apply to this project about the lake of syntax highlight,...

  10. yunxiu0621 commented on Jan 30, 2024

    @yunxiu0621

    I use BeautifulSoup analyse xml, then it can work below.

    @component
    def DataList(items, functest=None, filter_by_priority=None, sort_by_priority=False):
        if filter_by_priority is not None:
            items = [i for i in items if i["priority"] <= filter_by_priority]
        if sort_by_priority:
            items = sorted(items, key=lambda i: i["priority"])
        list_item_elements = [f"""<li key="{i["id"]}">{i["text"]}</li>""" for i in items]
        test = "<sdfa>"
        return """
            <ul>
                abcdedfe
                {functest()}
                {"".join(list_item_elements)}
                {test}
                {test}
                def
                ""{""}""
                <div>test</div>
            </ul>
        """
    
    @component
    def TodoList(text=""):
        def functest():
            return ("test-----------------------abc")
        tasks = [
            {"id": 0, "text": f"{text} Make breakfast3", "priority": 0},
            {"id": 1, "text": f"{text} Feed the dog", "priority": 0},
            {"id": 2, "text": f"{text} Do laundry", "priority": 2},
        ]
        return """
            <section>
                <h1>My Todo List</h1>
                <DataList items={tasks} functest={functest} filter_by_priority={1} sort_by_priority={True} />
            </section>
        """
    
    @component
    def Test():
        a = 2
        b = 3
        return """
            <h1 id="1" class_name="abc">My Todo List {a + b} Test PSX</h1>
            <ul id="2">
                <li id="5">"Design {23} a cool new app</li>
                <li id="4">Build"</li>
                <li>"Share it with the world!</li>
            </ul>
            <TodoList class_name="abc" />
            <TodoList text="abcd">
                <div>abc</div>
            </TodoList>
            <img
                src="https://picsum.photos/id/237/500/300"
                class="img-fluid"
                style="width: 50%; margin-left: 25%;"
                alt="Billie Holiday"
                tabindex="0"
            />
        """
  11. hasansezertasan commented on Feb 2, 2024

    @hasansezertasan

    There is a project that this issue brought to my mind.

    RudreshVeerkhare/ReactPy: React implementation in Python 3, which runs on the client-side.

    I have never used this project, but I have examined its examples. It allows creating files with the .pyx extension and in these files, you can write HTML with Python, without doing any string formatting.

    And I also want to highlight these resources:

    And finally, I love Python syntax and hate micro-syntaxes (Jinja counts).

  12. yunxiu0621 commented on Feb 3, 2024

    @yunxiu0621

    There is a project that this issue brought to my mind.

    RudreshVeerkhare/ReactPy: React implementation in Python 3, which runs on the client-side.

    I have never used this project, but I have examined its examples. It allows creating files with the .pyx extension and in these files, you can write HTML with Python, without doing any string formatting.

    And I also want to highlight these resources:

    And finally, I love Python syntax and hate micro-syntaxes (Jinja counts).

    ReactPy is client side but reactpy is server side. There are two ways to analyze pyx, BeautifulSoup and pypeg2. Then how to use js/ts. component library may be important, reactpy get the easy way get it.

  13. hasansezertasan commented on Feb 3, 2024

    @hasansezertasan

    ReactPy is client side but reactpy is server side. There are two ways to analyze pyx, BeautifulSoup and pypeg2. Then how to use js/ts. component library may be important, reactpy get the easy way get it.

    Yep, thanks for informing 🤩.

  14. hasansezertasan commented on Feb 6, 2024

    @hasansezertasan

    I just discovered another package that lets you write HTML inside python, check it out: twidi/mixt: Write html components directly in python and you have a beautiful but controversial MIXTure

  15. Archmonger commented on Feb 6, 2024

    @Archmonger
    ContributorAuthor

    I can see there's a pretty heavy want for a JSX style syntax for ReactPy.

    Ideally we would have added support for this once Python and code editors (such as VS Code) add support for syntax highlighting on strings. But perhaps we should release support for it for early adopters to test it out.

  16. arindampradhan commented on May 18, 2024

    @arindampradhan

    Any progress related to this

    Need a transpiler with .pyx extension

    Currently rust has it already implemented in their yew framework https://yew.rs/docs/concepts/html
    Javascript has jsx already

    There will be a need for transpilers so that a python file can import json, css as string
    Without a transpiler this project this library is very hard to use

    (
        <div>
            <div data-key="abc"></div>
            <div class="parent">
                <span class="child" value="anything"></span>
                <label for="first-name">{ "First Name" }</label>
                <input type="text" id="first-name" value="placeholder" />
                <input type="checkbox" checked=true />
                <textarea value="write a story" />
                <select name="status">
                    <option selected=true disabled=false value="">{ "Selected" }</option>
                    <option selected=false disabled=true value="">{ "Unselected" }</option>
                </select>
            </div>
        </div>
    )
    

    With transpiler

    import reactpy import render
    
    def hello_world():
        return <h1>Hello world</h1>
    
    render(hello_world, '#root')

    Should transpile to

    import reactpy import render
    
    def hello_world():
        return h('h1', 'Hello world')
    
    render(hello_world, '#root')
  17. Archmonger commented on Feb 9, 2025

    @Archmonger
    ContributorAuthor

    An update to this issue: Looks like the tag string PEP has been pushed aside in favor of a new template string PEP.

    Additionally, it has been merged into Python 3.14.

  18. mkzeender commented on May 26, 2025

    @mkzeender

    Hi! I just finished creating a backport of t-strings for python<3.14. This will be helpful, especially after the release of 3.14 because it will be compatible with all the existing python tools (like linters and static type checkers).

  19. Archmonger commented on Feb 7, 2026

    @Archmonger
    ContributorAuthor

    @mkzeender Are you willing to take a stab at this issue ticket (leveraging your backport)?

    An initial implementation was created by Ryan several years ago, but it may need some tweaks.

  20. mkzeender commented on Feb 8, 2026

    @mkzeender

    @Archmonger I'll take a stab at it, yeah. But just to be clear, are we going the "html inside of template strings" route,

    For example:

    from .nodes import my_node
    
    def hello_world():
        return t"""
               <my_node>
                   <h1>Hello world</h1>
               </my_node>"""

    which would have the advantage of being more compatible with existing python tools.

    Or are we going the route of "dedicated syntax that extends the python language" i.e.

    from .nodes import my_node
    
    def hello_world():
        return (
            <my_node>
                <h1>Hello world</h1>
            </my_node>
        )

    I assume we are talking about the latter, but I want to make sure.

  21. Archmonger commented on Feb 9, 2026

    @Archmonger
    ContributorAuthor

    We definitely would go the tag string route.

    Ryan and I have discussed that it would not be reasonable to think this repo should cause a design overhaul of all Python type checkers. We need to conform to Python standards, and in this case it's tag strings.

    In the worst case, we would have to PR several IDEs (ex. VS Code) to add syntax awareness.

  22. mkzeender commented on Feb 19, 2026

    @mkzeender

    Working on an implementation for the template-string compiler. The next step is figuring out the best way to integrate into reactpy, so I have a few things we will need to decide on:

    1. What to do with children of user-components? Should we pass them as a "children" argument? Should we remove children if they are whitespace-only? (if not, the children will inevitably contain a lot of whitespace depending on how the code is formatted). Should we disallow children entirely?

    2. Ideally, I think reactpy should allow a Template to be returned from components, and passed as children to html nodes. E.g., a Template object should be allowed anywhere that a VdomDict would. If we go this route, it will require tighter integration with the core of reactpy. If we don't, then the user would be required to manually call an html() function on every template string they create, which would be extremely verbose in practice, especially in more dynamic code where only one element is being created at a time. i.e. why write return html(t'<h1>{value}</h1>') when you could just do html.h1(value). But return t'<h1>{value}</h1>'

    3. The future-tstrings package probably shouldn't be a mandatory dependency, but should it be an optional dependency?

  23. Archmonger commented on Feb 19, 2026

    @Archmonger
    ContributorAuthor
    1. I believe I might be misunderstanding your description. Could you to provide a more context/examples on this? But as a general guideline for this repository, we try our best to maintain visual/behavioral similarity to ReactJS equivalents (within technical constraints). So in this case, stripping out indentation sounds reasonable.
    2. I agree, I'd imagine it would need deep integration with ReactPy core to be usable within existing Python infrastructure, while maximizing developer convenience. Having support for return t'<h1>{value}</h1>' is the ultimate goal.
    3. It should be a required dependency, but only installed if the user is utilizing a Python version that does not have native T-String support.
  24. mkzeender commented on Feb 19, 2026

    @mkzeender
    1. For example, if I write t'<{MyComponent}>Hello {user_name}</{...}>' What should happen to "Hello " and user_name? In ReactJS, MyComponent could be defined to unpack the "children" member of the object passed to it. Python doesn't have object unpacking, but we do have keyword arguments, so I think we should check if the component's signature includes a "children" argument and if so, pass the children to it as a list.

    Furthermore, I was pondering what should happen to the whitespace in

    t""" <div>
       Hello world{bang} Wow!
       {lipsum}
       <b>Goodbye</b>
    </div>
    """
    

    I did some experiments with JSX and I'm starting to understand the ins and outs of whitespace handling there so I'll keep working on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority-2-moderateShould be resolved on a reasonable timeline.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions