alphagov / govuk-frontend

GOV.UK Frontend contains the code you need to start building a user interface for government platforms and services.
https://frontend.design-system.service.gov.uk/
MIT License
1.16k stars 320 forks source link

Add helper for creating DOM elements #2894

Open romaricpascal opened 1 year ago

romaricpascal commented 1 year ago

What

Add a createElement (naming up for discussion) helper function to act as a shortcut for creating elements and assigning them attributes, props and/or children (scope to be defined). Something along the lines of the following (in a syntax more adapted to the browsers we support):

export function createElement (tagName, {attributes = {}, properties = {}, children = []} = {}) {
  const el = document.createElement(tagName)

  Object.entries(attributes).forEach(([attributeName, attributeValue]) => {
    el.setAttribute(attributeName, attributeValue)
  })

  // This can help set `innerHTML` for example
  Object.entries(properties).forEach(([propertyName, propertyValue) => {
    el[propertyName] = propertyValue
  })

  children.forEach(child => {
    el.appendChild(child)
  })

  return el
}

Why

A lightweight version of such helper has been added to de-clutter tests for the CharacterCount internationalisation: https://github.com/alphagov/govuk-frontend/blob/character-count-i18n/lib/dom-helpers.mjs. The Accordion and CharacterCount create a few elements themselves when initialised which would get a bit leaner.

Who needs to work on this

Developers

Who needs to review this

Developers

Done when

romaricpascal commented 1 year ago

Linking @36degrees' comment on the PR that sparked the creation of this issue: https://github.com/alphagov/govuk-frontend/pull/2887/files#r983699156.

romaricpascal commented 1 year ago

A further note that the dom-helpers.mjs file has gained a second helper to create a DocumentFragment out of an HTML String to scaffold larger structures, that's worth discussing at the same time:

export function createFragmentFromHTML (html) {
  const template = document.createElement('template')
  template.innerHTML = html
  return template.content.cloneNode(true)
}
romaricpascal commented 3 months ago

Missed to share that I had explored the concept of creating elements in a more thorough way outside of govuk-frontend at the time. There may be useful code in there we could look at.

36degrees commented 3 months ago

Having spent a bit of time looking at the JavaScript for the accordion recently I can see more of a need for this than maybe I appreciated before.

I've pushed a branch with a commit that shows what it might look like in practise (although just accepting attributes for now) in case it's useful in the future: https://github.com/alphagov/govuk-frontend/commit/13ef8cdfc686cd863f9490e113f5b3be3a0e5613

romaricpascal commented 3 months ago

Probably one step too far, but given our tool chain has Babel set up to compile our sources, we could use the transform-react-jsx plugin to automatically transform JSX markup into a createElement calls 😊