Miss any of our Open RFC calls?Watch the recordings here! »

react-jsx-template

1.0.13-0 • Public • Published

react-jsx-template

react + react-jsx-template = modularity and encapsulation

React component for style encapsulation. It helps you create components with scoped styles, also compatible with material-UI components. We would agree that writing CSS for React would be a lot easier if we didn't have to worry about conflicting style rules, this component does exactly that.

If you're a Vue.js developer transitioning to React.js you will love this powerful yet simple component. It works like the <template> tag in Vue.js, but in this case you write both your markup and stylesheet inside it.

You might want to read more about how this component achieves encapsulation, or move on you're fine without this paragraph. 'react-jsx-template' works with the Shadow DOM API and essentially renders the content of your component within the Shadow DOM of a 'root' element. Ok that's enough talk, proceed to see how all this might be useful to you.

installation

If you have node installed on your computer, run;

npm install react-jsx-template

peer dependencies

This package requires that you have the following packages installed in your project;

  • Material-UI components version: ^"4.10.1" for reusable UI components. More information here

    to install run;

    npm install @material-ui/core
  • React library. It comes by default if you scaffold your project on CRA. More information here

    to install run;

    npm install react

Usage

Quick links

| Structuring your markup | Custom setup | Styling the root element | Variable CSS selectors | Variable CSS properties | Variable CSS values | Variable CSS properties | Dynamic pseudo-element styling | Dynamic media queries

Now we're all setup, to use the 'react-jsx-template' import it at the top of your script.

import {Template} from 'react-jsx-template'

Structuring your markup

You can then use it in the render function of your component by structuring it this way;

// component showing how to structure your markup
render() {
    return (
        <Template>
 
            {/* the root element can be any element or component except <style> */}
            <root>
 
                {/* this is where the content of your component goes */}
                <p>Hello world!</p>
 
                <p>
                    Everything within the 'root' element will be regarded as the 
                    content of this component.
                </p>
            </root>
 
            <style>
            {`
                selector {property: value;}
            `}
            </style>
        </Template>
    )
}

Essentially, our <template> should contain 2 child elements;

  • The root element, where we write our markup.
  • A <style> element to contain our CSS rules.
// component with scoped styles, using material-ui component library
render() {
    return (
        <Template>
            <div> {/* this div is the root element */}
 
                {/* this is the content */}
                <p>Red colored content, try it</p>
            </div>
 
            <style>
            {`
                div {color: red;}
            `}
            </style>
        </Template>
    )
}

The <Template> tag does not get mounted to the DOM, so if you check your dev tools you won't see it. However, the root element gets mounted to the DOM and contains all the other elements of our component.

Custom setup

You can use material-ui styled components by default, the inline styles will be preserved. To use a different component library, you need to setup a custom 'StylesProvider' the setup is explained below.

Create a template.js file in your './src' directory, and write the following code in it;

// template.js
import {StylesProvider} from 'location of user defined styles provider'
import {initializeTemplate} from 'react-jsx-template'
 
const Template = initializeTemplate(StylesProvider)
export default Template

You can now use it in your components;

// your component
import Template from './template.js'
import {Item} from 'other component library'

and in the render function we can have something like this;

// component with scoped styles, using other component library
render() {
    return (
        <Template>
            <Item {/* this component is the root element */}
             display = 'flex'
             justifyContent = 'space-between'
             width = '100%'
             padding = '0.5rem'
             background = '#06397d'
            >
                <Item className='red box' height='100%'></Item>
                <Item className='yellow box' height='100%'></Item>
            </Item>
 
            <style> {/* user defined style rules override component library's inline styles */}
            {`
                .red {background: #911f1e;}
 
                .yellow {background: #fcdfa3;}
 
                .box {height: 50%;}
            `}
            </style>
        </Template>
    )
}

Styling the root element

Styling the root element of your component can be done using the ':host' selector. This is because encapsulation is done using the shadow DOM API under the hood. You don't need prior knowledge of that to use this component, but you can check that out later if you want.

// styling the root element
render() {
    return (
        <Template>
            <div> {/* this is the root element */}
                The root element has red text.
            </div>
 
            <style>
            {`
                :host {color: red;}
            `}
            </style>
        </Template>
    )
}

Variable CSS selectors

We have our CSS inside our JS file, and this allows us to play around with the CSS, using javascript variables as CSS selectors in our component styling, take a look;

// JS variable as CSS selector
render() {
    // we can change the value of 'target' dynamically to 'green' or 'blue'
    let target = 'red'
 
    return (
        <Template>
            <div>
                <p className={target}>
                    This paragraph has a variable className and a CSS selector that always matches its className and applies persistent styling rules, eliminating the need for an additional className.
                </p>
            </div>
 
            <style>
            {`
                p.${target} {...persistent styling rules}
 
                .red {color: red;}
                .green {color: green;}
                .blue {blue: blue;}
            `}
            </style>
        </Template>
    )
}

Variable CSS properties

We can also use this concept to implement dynamic CSS properties in our component styles

// JS variable as CSS property
render() {
   // we can dynamically alternate the value of 'property' between 'border-color' and 'color'
   let property = 'border-color'
 
   return (
       <Template>
           <div>
               <p className='someClass'> This paragraph can either have a blue text color or a blue border color</p> 
           </div>
 
           <style>
           {`
               .someClass {${property}: blue;}
           `}
           </style>
       </Template>
   )
}

Variable CSS values

With the same technique, we can have dynamic CSS values in our component styles

// JS variable as CSS value
render() {
   // we can dynamically change 'value'
   let value = '10%'
 
   return (
       <Template>
           <div>
               <p className='someClass'> The CSS value of the height of this paragraph can be directly manipulated using Javascript.</p> 
           </div>
 
           <style>
           {`
               .someClass {height: ${value};}
           `}
           </style>
       </Template>
   )
}

Dynamic pseudo-element styling

This makes controlling the CSS styles of pseudo-elements a breeze, see an example;

// JS variable as CSS selector
render() {
    // we can dynamically change the value of 'size' to 'medium' or 'large'
    let size = 'small'
 
    return (
        <Template>
            <div>
                <p className={size}>The :before pseudo-element of this paragraph has persistent and variable
                style rules.</p>
            </div>
 
            <style>
            {`
                .${size}:before {
                    content: '';
                    position: absolute;
                    height: 10px;
                    background: crimson;
                }
 
                .small:before {width: 10%;}
                .medium:before {width: 25%;}
                .large:before {width: 40%;}
                .x-large:before {width: 60%;}
            `}
            </style>
        </Template>
    )
} 

Dynamic media queries

We can also experiment with dynamic media queries, see an example;

// JS variable as media query breakpoint
render() {
    // we can dynamically adjust the breakpoint of the media query, thereby activating or deactivating it.
        let breakpointMobile = '720px'
        let breakpointDesktop = '1280px'
 
    return (
        <Template>
            <div>
                <p> You can alter the breakpoint to display desktop view on mobile and vice-versa. </p>
            </div>
            
            <style>
            {`
                @media screen and (max-width: ${breakpointMobile}) {
                    // mobile styling
                }
 
                @media screen and (min width: ${breakpointDesktop}) {
                    // desktop styling
                }
            `}
            </style>
        </Template>
    )
} 

For additional support, follow me on twitter @onepetercollins or github. You can share your ideas and cool projects, I'd love to see them.

If you made it this far, this component is useful to you. I will appreciate your donations towards the maintenance of this package. Email me

Install

npm i react-jsx-template

DownloadsWeekly Downloads

1

Version

1.0.13-0

License

ISC

Unpacked Size

26.7 kB

Total Files

6

Last publish

Collaborators

  • avatar