Description
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 toFoo
. - 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 aschildren
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 theReact.Basic.createElement
straightforward. It simply takes aprops
record and if it happens to have achildren
attribute it will be passed tocreateElement
via apply. In other words it unmagics the weird "convinience" thatReact.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 totypes.json
and make it so that the codegen spews out the whole module (so that it can be regenerated vianode 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?