Description
Current Situation
Currently the vdom
element constructor and component constructors have different interfaces. Component constructors are effectively just the same as the functions which define them. For the vdom
constructor though we pass vdom(tag, attrs_dict, *children)
. The fact that these two constructors have different interfaces won't play well with this tagged strings PEP.
Proposed Actions
In anticipation of the work from the tagged strings PEP we should have a unified interface for constructing elements and components. I think the best way to do this would be to effectively copy the interface for React's functional components.
When constructing a component or element the interface would be:
constructor(*children, key=..., **attributes)
However the definition for the constructor would be:
def constructor(children: list[any], **attributes: any): ...
In the function definition, *children
gets bundled together into a special children
argument that gets passed to the function. Component functions without a children
argument then do not support *children
. Additionally (as is currently the case) the special key
parameter is hidden and handled separately.
One wrinkle in this is that the attribute for most user defined components will be snake_case while the attributes for standard HTML elements are camelCase. I suspect this will be confusing for most users. As a result, I suggest that, for standard HTML elements, we include a snake_case to camelCase conversion. Thus something like div(background_color)
would be treated the same as div(backgroundColor=...)
.
This will be a relatively large change, so we will provide a way for users to transition to the new interface.
Notes
We should probably do #545 at the same time. So we'd add a fallback
kwarg to the constructor:
constructor(*children, key=..., fallback=..., **attributes)