Skip to content

DOM Rendering

esr360 edited this page Feb 16, 2020 · 4 revisions

Changing Rendered HTML Tag

By default, <Module> and <Component> will render a <div> tag to the DOM. You can specify a different HTML tag to use by passing the tag name to a tag prop:

<Module styles={styles} tag='section'>
  <Component name='heading' tag='h3'>Heading</Component>
  <Component name='text' tag='p'>Some text</Component>
</Module>

A Component with no name prop will use the value of an existing tag prop instead:

<Module styles={styles} tag='form'>
  <Component tag='fieldset'>
    <Component tag='label'>...</Component>
    <Component tag='input'>...</Component>
  </Component>
  ...
</Module>

This effectively lets you style tags (scoped to the Module) the same way you can style Components:

const styles = {
  fieldset: {
    // ...some styles
  },
  label: {
    // ...some styles
  },
  input: {
    // ...some styles
  },
  p: {
    // ...some styles
  }
}

Supplying a href prop without a tag prop will automatically render an anchor element

Supplying Own React Component

You can supply a React Component to render instead a div/HTML tag, as long as the Component you supply ultimatly renders something to the DOM (whatever Component you supply here must have a current property on its ref that has a DOM node as its value):

<Module styles={styles} component={MyReactComponent}>
  ...
</Module>

If you need to supply some props to this Component, you can pass the value as an array; the first item being your Component, and the second item being your props (as an object):

<Module styles={styles} component={[MyReactComponent, { myProp: 'myValue' }]}>
  ...
</Module>

This is useful for wrapping UI Modules you may take from third parties (e.g. react-table).

DOM Output

Class Name

Overview

One of the goals of Lucid is to ensure the rendered DOM is still clean, predictable and readable. Lucid achives this by outputing classes that adhere to the BEM Naming Convention (and can be loosley configured).

Consider the following example:

export default () => (
  <Module name='card'>
    <Component name='title' large primary>Card Title</Component>
    <Component name='content'>Card Content</Component>
  </Module>
);

This would output HTML with the shown classes (the actual rendered HTML may have additional attributes):

<div class="card">
  <div class="card__title card__title--large card__title--primary">Card Title</div>
  <div class="card__content">Card Content</div>
</div>

By setting the singleClass option to true you can change the above output to:

<div class="card">
  <div class="card__title--large--primary">Card Title</div>
  <div class="card__content">Card Content</div>
</div>

Learn more about Sub-Components and DOM classes

This means that there is benefit in using Lucid merely to create clean DOMs (i.e, without using the Styling aspect).

Generate CSS Classes

You can enable/disble the generation of classes when using Lucid.

Pass the generateClasses property to your module's configuration

const config = {
  generateClasses: true,
  ...
}

const MyModule = () => (
  <Module name='my-module' styles={...} config={config}>
    <Component name='my-component'>My Component</Component>
  </Module>
);
Output
<div class="my-module">
  <div class="my-module__my-component">My Component</div>
</div>

This option can be set globally by adding it to your theme

Modifiers

Props which have a boolean value of true will be treated as modifieirs.

const MyModule = () => (
  <Module name='my-module' styles={...} config={config} alpha>
    <Component name='my-component' fizz buzz>My Component</Component>
  </Module>
);
Output
<div class="my-module--alpha">
  <div class="my-module__my-component my-module__my-component--fizz my-module__my-component--buzz">
    My Component
  </div>
</div>
Single Class

Instead of generating separate classes for each modifier, you can instead generate a single class.

Pass the singleClass property to your module's configuration

const config = {
  generateClasses: true,
  singleClass: true,
  ...
}

...
Output
<div class="my-module--alpha">
  <div class="my-module__my-component--fizz--buzz">
    My Component
  </div>
</div>

This option can be set globally by adding it to your theme

Customize Naming Convention

You can customize both the Component glue (default: __) and modifer glue (default: --):

const config = {
  generateClasses: true,
  singleClass: true,
  componentGlue: '_',
  modifierGlue: ' '
  ...
}

const MyModule = () => (
  <Module name='my-module' styles={...} config={config} fizz>
    <Component name='my-component' foo bar>My Component</Component>
  </Module>
);
Output
<div class="my-module fizz">
  <div class="my-module_my-component foo bar">My Component</div>
</div>

These options can be set globally by adding them to your theme

HTML Attributes

In order to keep bundle size down, the Lucid Components accept the following DOM-affecting props:

If you need to pass any other props/attributes to the rendered DOM node, you should pass them to the attributes prop:

<Module styles={styles} tag='form' attributes={{ method: 'post'}}>
  ...
</Module>

Whilst this isn't the best DX (you'd ideally be able to pass attribute directly), it keeps the bundle size down as it avoids having to keep a list of valid HTML attributes in the source.

Generate Data-Attributes

By default, Lucid will output a data-module attribute for <Module>s, and a data-component attribute for <Component>s and <SubComponent>s:

const MyModule = () => (
  <Module name='my-module'>
    <Component name='my-component'>
      <SubComponent name='my-subComponent'>
        ...
      </SubComponent>
    </Component>
  </Module>
)
Output

<SubComponents> will also output a boolean data-sub-component attribute

<div data-module="my-module">
  <div data-component="my-component">
    <div data-component="my-subComponent" data-sub-component>
      ...
    </div>
  </div>
</div>

To disable this feature, pass a generateDataAttributes property to your module's configuration and set it to false:

const config = {
  generateDataAttributes: false,
  ...
}

This option can be set globally by adding it to your theme

Clone this wiki locally