WordPress and React

In version 5.0 WordPress introduced Gutenberg, a block-based editor with a much more modern user interface than the classical editor.

Gutenberg is made with React, so after this version WordPress ships with the basic React libraries included, namely react.min.js and react-dom.min.js.

Moreover, WordPress provides its own implementation of React in wp.element object, which contains functions such as render, createElement, useState etc.

WordPress loads React libraries only when necessary, so this happens by default when editing a post or page in the Dashboard using Gutenberg.

However it is possible to load them anywhere on-demand, even in the front-end just by adding the dependency ‘wp-element’ when enqueueing a script.

Material UI

Material UI is an implementation of Google’s Material Design with React. Since WordPress supports React, it is theoretically possible to use Material UI with WordPress. Here is how.

The guide in this article describes how to insert react elements inside a WordPress page using a shortcode.

Here are the basic steps the article follows:

  1. It creates the React code using JSX and builds it, generating a single main.js file. All React DOM is rendered inside a container element.
  2. It enqueues main.js file when the WordPress page loads using wp_enqueue_scripts filter. It adds ‘wp-element’ dependency when enqueueing the file, so that WordPress loads React library.
  3. The shortcode outputs the div container element, inside which the React DOM is rendered.

So, when the page loads, the React DOM is rendered inside the container that was created by the shortcode.

We can easily extend the React code to use Material UI components. The process is the same. We just build a new main.js file.

Here is an example render of WordPress File Upload plugin, which uses Material UI components for its upload form:

However, there is a catch.

Conflicts with WordPress Themes

Material UI is a design, having its own rules about fonts, colors, margins and styling in general. On the other hand, WordPress uses themes to set the appearance of a website, and themes impose their own styling rules.

So there is a conflict!

When we load the page, we notice that the Material UI components do not look as expected. They are distorted.

Here is how the above upload form of WordPress File Upload plugin looks like with Hestia WordPress theme if no actions are taken about this conflict:

We notice that the size of components has changed and they have lost their nice alignment. Moreover the day buttons in the date picker have a pink shadow, which has been imposed by Hestia theme.

The reason of these distortions is that the WordPress theme’s CSS rules override Material UI’s rules.

Unfortunately, this is something that we cannot predict. Every theme has its own way of setting CSS rules, so it is unknown how they would affect the Material UI components.

However, when we are using the Material UI components inside a WordPress plugin, we want a generic solution that will resolve this problem for all themes.

There are two ways of resolving this problem:

  1. Make Material UI CSS rules stronger than the theme’s, so that they always override it.
  2. Isolate Material UI components from the page, but only as regards the CSS styles. We want the components to continue interacting with the rest of the page normally.

WordPress File Upload has made a deep research on this issue and has tested both solutions. Each one has its pros and cons, however the most efficient and universal is the second one, the isolation of Material UI components only as regards CSS styling.

The Shadow DOM Solution

Isolation can be achieved using Shadow DOM, a key part of Web components encapsulation.

Shadow DOM provides a way to attach a hidden separated DOM to an element.

The meaning of ‘hidden’ is that the attached separated DOM does not inherit the styles of the main DOM, and this is exactly the type of isolation that we want.

So, if we render the Material UI components inside a container element that resides inside a shadow DOM, then they will not be affected by the theme’s CSS.

Here is a part of WordPress File Upload plugin HTML structure, when it is configured to use shadow DOM:

All the plugin’s HTML is rendered inside an open shadow DOM, under the main container element of the plugin with id “wordpress_file_upload_block_1”.

The Material UI components of the upload form are rendered in separate div containers inside the shadow DOM. Here we can see part of the Material UI component that shows the selected filename of an uploaded file. It is rendered inside a div container with id “r_wfu_textbox_1”.

Implementing the Shadow DOM solution is actually very easy. Here are the basic steps:

  1. We put all the HTML code that we want to isolate, or just the container where we want to render the Material UI components, inside a template element. A <template> is a special HTML element that does not render the contained HTML code immediately but only when needed.
  2. We create the shadow DOM under an element using attachShadow() Javascript function.
  3. We append inside the shadow DOM the template content.

When the page is rendered, the components inside the shadow DOM will not be affected by the CSS rules outside the shadow DOM.

Caveats of Shadow DOM Solution

There are some things to consider when using Shadow DOM.

First, elements inside the shadow DOM cannot be referenced in Javascript code as before, using document.getElementById(), document.querySelector() or similar functions, because their root element is not the document element, but the shadow DOM. So instead of document we need to use the object returned by attachShadow() function.

Second, using CSS code that combines elements inside and outside the shadow DOM is tricky. In the above code of WordPress File Upload plugin, suppose that we wanted to set the visibility of component with id “r_wfu_textbox_1”, which resides inside the shadow DOM, to ‘hidden’, based on a custom class “hide-filename” of the article element with id “post-261”, which resides outside the shadow DOM.

If we didn’t have a shadow DOM, it would look like this:

article#post-261.hide-filename div#r_wfu_textbox_1 {
  visibility: hidden;
}

However, because of the shadow DOM, the CSS selector article#post-261.hide-filename div#r_wfu_textbox_1 will not work.

CSS3 has a special pseudo-class selector for such cases, :host-context(). Here is how the correct CSS code looks like:

:host-context(article#post-261.hide-filename) div#r_wfu_textbox_1 {
  visibility: hidden;
}

The problem with :host-context() is that it is not supported yet by all browsers, as shown here. Safari and Firefox do not support it yet.

So, until it is widely supported, developers need to find other ways to cover such cases.

For additional information or questions, do not hesitate to contact us.

The Iptanus Team

How to Use Material UI in WordPress Plugins

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.