Skip to content

Consider representing attributes with rows for DOM elements #147

Open
@ethul

Description

@ethul

Currently, DOM elements accept an array of Props. An alternative to this could be to define a row representing the known attributes one may pass as props to a DOM element. Using a row was briefly mentioned in #113 (comment).

For instance, we could define two rows: one for HTML attributes and one for SVG attributes. Going this route, we would need a way to handle passing event handler callbacks. Also, if we wanted an attribute to have a type other than a primitive one or one known to React, then we would need a way to map the attribute's value to something React can use.

I think using rows could prove to be nicer in terms of syntax and perhaps a bit more convenient. I wanted to bring up this idea to see if there is interest in going this route. I'd be happy to discuss other ideas or dig in deeper with rows if there is interest. Any comments, questions, or suggestions are most welcome.

Also, below are some options for what this could look like. Option 1 presents passing a record where the row must be a subrow of all HTML attributes. Option 2 is similar, but passes a Data.Record.Builder. Using a builder we have the opportunity to pass data types other than primitive ones; e.g., instead of the target function accepting a String, we could make a Target data type and map it to a String in the function. Just a couple of ideas, others are most welcome.

Option 1 - Records

type HTMLAttributes r
  = ( href :: String
    , target :: String
    | r
    )

a
  :: forall r s t
   . Union r t (HTMLAttributes s)
  => Record r
  -> Array React.ReactElement
  -> React.ReactElement
a props children = React.createElementTagName "a" props children

foo :: React.ReactElement
foo =
  a
    { href: "https://github.com/purescript-contrib/purescript-react"
    , target: "_blank"
    } [ ... ]

Option 2 - Builder

type HTMLAttributes r
  = ( href :: String
    , target :: String
    | r
    )

href
  :: forall r
   . RowLacks "href" r
  => String
  -> Builder { | r } { href :: Int | r }
href = Builder.insert (SProxy :: SProxy "href")

target
  :: forall r
   . RowLacks "target" r
  => String
  -> Builder { | r } { target :: String | r }
target = Builder.insert (SProxy :: SProxy "target")

a
  :: forall r s t
   . Union r t (HTMLAttributes s)
  => Builder { } (Record r)
  -> Array React.ReactElement
  -> React.ReactElement
a builder children = React.createElementTagName "a" (Builder.build builder {}) children

foo :: React.ReactElement
foo =
  a
    ( href "https://github.com/purescript-contrib/purescript-react"
      >>> target "_blank"
    ) []

// @natefaubion

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