Skip to content

Childish DOM contemplations #49

Closed
Closed
@zudov

Description

@zudov

When we started using react-basic, we didn't like some aspects of React.Basic.DOM interface. Having to pass HTML children as a { children } didn't map well to conventional thinking about DOM tree, made hard adding properties to elements that didn't have them before and seemed overly verbose. I haven't found any designated discussion of the DOM interface, so I thought I'll open that issue to gather information.

JSX and createElement

I haven't really dealt with React before, so I had to dig around a bit to understand the motivation behind the current design. Some key points:

  • React components would often want to contain some DOM that's passed in by their parent. There is a convention to pass it through children property, unless something more advanced is needed.
  • JSX syntax provides a nice sugar on top of that convention. When one writes <Foo><h1>Bar</h1></Foo>, { children: <h1>Bar</h1> } would be passed to Foo.
  • For reasons unknown to me, React.createElement chooses to do some magic and allows to pass arbitrary amount of extra arguments that are all fitted into an array and passed to component as children prop.
  • Despite that the common usecase is that children prop is an array of JSX elements, it's fairly common to have other types there. React doesn't constrain that in any way (and even provides helpers to help dealing with variously typed children).
  • purescript-react-basic keeps the React.Basic.createElement straightforward. It simply takes a props record and if it happens to have a children attribute it will be passed to createElement via apply. In other words it unmagics the weird "convinience" that React.createElement provides.

Please complete me here if I skipped some important details/constraints.

React.Basic.DOM

As I learned DOM interface used to take children as argument, but it was changed to children as property.

I don't think there's such thing as perfect, right, or correct HTML DSL since it's largely a matter of usage scenario, style, and taste. There is always room for improvement and innovation (especially as we get new language features). It would be nice if react-basic provided a DOM interface that stands up to the motto ("opinionated and optimized for the most basic use cases") and expose the data needed to generate third-party DOM interfaces for whomever have different needs/opinions.

What needs to be exposed is the const types (we can put it in types.json and standalone codegen could just load it by url from github). Instead of const voids we can import html-void-elements. That would make it easy enough to make third-party libraries with DOM interfaces. Maybe react-basic could also accept merge requests with alternative DOM flavors (or make a -contrib library) as long as their design is concrete and reasoned.

React.Basic.DOM.Childish

To give it a try I tweaked the codegen slightly and generated a different flavor of HTML DSL. For now it's just committed to our codebase and we switched most of the code to use it. It can be found here. The design decisions are outlined in the commit message.

In this issue I wanted to:

  • Discuss what should the default DOM DSL looks like. I don't have any concrete demands on that, but I'd really love to hear about the experience of using react-basic for some view-heavy code. It's also interesting to know how did current design emerge and what was the experience of switching from children-as-argument to children-as-property.
  • Get a green light to refactor the codegen a bit. I mainly want to move the types dictionary to types.json and make it so that the codegen spews out the whole module (so that it can be regenerated via node codegen/index.js > src/React/Basic/DOM.purs
  • Discuss the preferred policy for "third-party DOM DSLs". Do we want to have them in a main repo or-contrib repo? Standalone libraries in random GitHub accounts or GitHub organization that hosts the "maintained" flavors?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions