Tag: Components

Demonstrating Reusable React Components in a Form

Components are the building blocks of React applications. It’s almost impossible to build a React application and not make use of components. It’s widespread to the point that some third-party packages provide you with components you can use to integrate functionality into your application.

These third-party components tend to be reusable. The difference between them and components you probably have in your application has to do with specificity.

Here’s what I mean. Say you run a company that sells polo shirts. There are two things you can do:

  1. You can produce polos that already have a design on them, or
  2. You can have the buyer choose the design they want.

Some fundamental things will be consistent, like all polos should be short-sleeved. But the user can pick variations of the shirts, such as the color and size. A short-sleeve polo would make a good React component in that case: it’s the same item with different variations.

Now let’s say you’re working on a login form. Like polo shirts, the form has consistent characteristics, but instead of size and color variations, we’d be looking at input fields, a submit button, perhaps even a lost password link. This can be componentized and implemented with variations in the inputs, buttons, links, etc.

Input Element Example

Let’s look at it from the perspective of creating an input field for your form. Here is how a typical text input will look like as a React component:

class Form extends React.Component {   this.state = {     username: ''   }      handleChange = (event) => {     this.setSate({ username: event.target.value })   }    render() {     return (       <input         name="username         type={type}         placeholder="Enter username"         onChange={this.handleChange}         value={this.state.username}       />     )   } }

To make this input element reusable in other places and projects, we’ll have to extract it into its own component. Let’s call it FormInput.

const FormInput = ({   name,   type,   placeholder,   onChange,   className,   value,   error,   children,   label,   ...props }) => {      return (     <React.Fragment>       <label htmlFor={name}>{label}</label>       <input         name={name}         type={type}         placeholder={placeholder}         onChange={onChange}         value={value}         className={className}         style={error && {border: 'solid 1px red'}}       />       { error && <p>{ error }</p>}     </React.Fragment>   ) }  FormInput.defaultProps = {   type: "text",   className: "" }  FormInput.propTypes = {   name: PropTypes.string.isRequired,   type: PropTypes.string,   placeholder: PropTypes.string.isRequired,   type: PropTypes.oneOf(['text', 'number', 'password']),   className: PropTypes.string,   value: PropTypes.any,   onChange: PropTypes.func.isRequired }

The component accepts certain props, such as the attributes that we need to make the input with valid markup, including the placeholder, value and name. We set up the input element in the render function, setting the attribute values as the props that are passed to the component. We even bind the input to a label to ensure they’re always together. You can see that we’re not making assumptions by predefining anything. The idea is to ensure that the component can be used in as many scenarios as possible.

This makes for a good component because it enforces good markup (something Brad Frost calls dumb React) which goes to show that not every component has to be some highly complex piece of functionality. Then again, if we were talking about something super basic, say a static heading, then reaching for a React component might be overkill. The possible yardstick for making something a reusable component probably ought to be when you need the same functionality in other parts of an application. There’s generally no need for a “reusable” component if that component is only used once.

We can make use of our input component in another component, the LoginPage.

class LoginPage extends React.Component {   state = {     user: {       username: "",       password: ""     },     errors: {},     submitted: false   };    handleChange = event => {     const { user } = this.state;     user[event.target.name] = event.target.value;     this.setState({ user });   };    onSubmit = () => {     const {       user: { username, password }     } = this.state;     let err = {};      if (!username) {       err.username = "Enter your username!";     }      if (password.length < 8) {       err.password = "Password must be at least 8 characters!";     }      this.setState({ errors: err }, () => {       if (Object.getOwnPropertyNames(this.state.errors).length === 0) {         this.setState({ submitted: true });       }     });   };    render() {     const {       submitted,       errors,       user: { username, password }     } = this.state;     return (       <React.Fragment>         {submitted ? (           <p>Welcome onboard, {username}!</p>         ) : (           <React.Fragment>             <h3>Login!</h3>             <FormInput               label="Username"               name="username"               type="text"               value={username}               onChange={this.handleChange}               placeholder="Enter username..."               error={errors.username}               required               className="input"             />              <FormInput               label="Password"               name="password"               type="password"               value={password}               onChange={this.handleChange}               placeholder="Enter password..."               error={errors.password}               className="input"               required             />              <Button               type="submit"               label="Submit"               className="button"               handleClick={this.onSubmit}             />           </React.Fragment>         )}       </React.Fragment>     );   } }

See how LoginPage uses the FormInput twice? We’re using it both as the text input for a username and another text input for a password. If we want to make any changes to how the input functions, we can make those changes inside the FormInput component file we created and they will be applied to every instance where the input component is used. That’s the fundamental upside to having reusable components: you don’t have to repeat yourself.

Even the errors are displayed from the FormInput component.

The onSubmit function first validates the user object which we get from the form, ensuring that it fits the structure that there is a value for username. Notice that we can even extend the input’s functionality, like we did to check that the password contains at least eight characters.

If you look at the code, you’ll see a have a Button component in there. That’s not the same as a HTML <button> element, but instead another component that takes the props that define the type of button we want (submit, reset, button), its class name, what to do on click, and the label. There are lots of other button attributes we could integrate to enforce whatever standard is needed.

const Button = (props) => (   <button     type={props.type}     className={props.className}     onClick={props.handleClick}   >     {props.label}   </button> )

Here’s our final login form when all of our components are put together.

See the Pen
Reusable Button Component
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.


Wanna give this a try yourself? Try working on a reusable <select> element. If that’s too difficult, you can start with a <textarea> element, then perhaps a checkbox before hopping over to <select>. The key idea is to make it generic. I’ll like to see what you came up with, so link up your work in the comment section!

The post Demonstrating Reusable React Components in a Form appeared first on CSS-Tricks.

CSS-Tricks

, , , ,

Weekly Platform News: CSS ::marker pseudo-element, pre-rendering web components, adding Webmention to your site

Šime posts regular content for web developers on webplatform.news.

In this week’s roundup: datepickers are giving keyboard users headaches, a new web component compiler that helps fight FOUC, we finally get our hands on styling list item markers, and four steps to getting webmentions on your site.

Using plain text fields for date input

Keyboard users prefer regular text fields over complex date pickers, and voice users are frustrated by the native control (<input type="date">).

Previously, I have relied on plain text inputs as date fields with custom validation for the site, typically using the same logic on the client and the server. For known dates — birthdays, holidays, anniversaries, etc. — it has tested well.

(via Adrian Roselli)

Pre-rendering web components

Stencil is a “web component compiler” that can be used to pre-render web components (including Shadow DOM) or hide them until they are fully styled to avoid the flash of unstyled content (FOUC).

This tool also makes sure that polyfills are only loaded when needed, and its Component API includes useful decorators and hooks that make writing web components easier (e.g., the Prop decorator handles changes to attributes).

import { Component, Prop, h } from "@stencil/core";  @Component({   tag: "my-component" }) export class MyComponent {   @Prop() age: number = 0;    render() {     return <div>I am {this.age} years old</div>;   } }

(via Max Lynch)

The CSS ::marker pseudo-element

When the CSS display: list-item declaration is applied to an element, the element generates a marker box containing a marker, e.g., a list bullet (the <li> and <summary> elements have markers by default).

Markers can be styled via the ::marker pseudo-element (useful for changing the color or font of the marker), but this CSS feature is currently only supported in Firefox.

(via Rachel Andrew)

Adding Webmention to your website

  1. Sign up on Webmention.io; this is a service that collects webmentions on your behalf.
  2. Add <link rel="webmention"> (with the appropriate href value) to your web pages.

    There are also Webmention plugins available for all major content management systems (CMS) if you prefer building on top of your CMS.

  3. Fetch webmentions from Webmention.io (via Ajax) to display them on your page.
  4. Use webmention.app to automate sending webmentions (when you publish content that includes links to other sites that support Webmention).

(via Daniel Aleksandersen)

The post Weekly Platform News: CSS ::marker pseudo-element, pre-rendering web components, adding Webmention to your site appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , , , ,
[Top]

Haunted: Hooks for Web Components

I was just chatting with Dave and he told me about Haunted. It’s hooks, but for native web components! Pretty cool. I think the existence of stuff like this makes using web components more and more palatable — particularly in that totally-native no-build-step-needed-at-all kinda way.

I get that there are all sorts of issues with web components, but the things that typically turn me away from them are a lack of nice templating and rerendering and no state management.

But we can knock those two out right quick these days…

First, making a component like <my-app> is perfectly comfortable:

import { html } from "https://unpkg.com/lit-html/lit-html.js"; import { component } from "https://unpkg.com/haunted/haunted.js";  function App() {   return html`     <div class="module">       Hello, World!     </div>   `; }  customElements.define("my-app", component(App));

Then we could add some state with hooks:

import { html } from "https://unpkg.com/lit-html/lit-html.js"; import { component, useState} from "https://unpkg.com/haunted/haunted.js";  function App() {   const [name, setName] = useState("Chris");   return html`     <div class="module">       Hello, $  {name}!     </div>   `; }  customElements.define("my-app", component(App));

The CodePen Challenge this week is using the Star Wars API, so let’s make a fetch request and use that to fill state. That’s a great use case for useEffect.

import { html } from "https://unpkg.com/lit-html/lit-html.js"; import { component, useState, useEffect } from "https://unpkg.com/haunted/haunted.js";  function App() {      const [planets, setPlanets] = useState([]);   useEffect(() => {     fetch('https://swapi.co/api/planets/?page=2')       .then(response => {         return response.json();       })       .then(data => {         let planets = data.results;         // remove ones with no diameters         planets = planets.filter(planet => planet.diameter !== "0");         setPlanets(planets);       });   }, []);    return html`     <style>       /* Shadow DOM styles */     </style>     <div class="all-planets">       $  {planets.map(planet => html`         <div class="planet" style="--dia: $  {planet.diameter}px">            <span class="planet-name">               $  {planet.name}            </span>         </div>       `)}     </div>   `; }  customElements.define("my-app", component(App));

That’s a proper little web component!

See the Pen
Star Wars API with Haunted.js
by Chris Coyier (@chriscoyier)
on CodePen.

The post Haunted: Hooks for Web Components appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

Why I don’t use web components

Here’s an interesting post by Rich Harris where he’s made a list of some of the problems he’s experienced in the past with web components and why he doesn’t use them today:

Given finite resources, time spent on one task means time not spent on another task. Considerable energy has been expended on web components despite a largely indifferent developer population. What could the web have achieved if that energy had been spent elsewhere?

The most convincing part of Rich’s argument for me is where he writes about progressive enhancement and the dependence on polyfills for using web components today. And I’m sure that a lot of folks disagree with many of Rich’s points here, and there’s an awful amount of snark in the comments beneath his post, but it’s certainly an interesting conversation worth digging into. For an opposing perspective, go read the very last paragraph in the last installment of our Web Components Guide, where author Caleb Williams suggests that there’s no need to wait to use web components in projects:

These standards are ready to adopt into our projects today with the appropriate polyfills for legacy browsers and Edge. And while they may not replace your framework of choice, they can be used alongside them to augment you and your organization’s workflows.

But all of this is a good reminder that hey: web components are a thing that we should be able to freely criticize and talk about without being jerks. And I think Rich does that pretty well.

Direct Link to ArticlePermalink

The post Why I don’t use web components appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

Components, yo.

I see VuePress just went 1.0. Explained simply, it’s a static site generator based on Vue. But of course, you work in Vue, which means you work in components.

All the modern JavaScript frameworks are component-based. Even when they disagree with each other about specific things (like how Svelte requires compilation), they all seem to agree on the model of working in components. React is all components. A popular static site generator for React is Next.js. The Vue version of that is Nuxt.js.

Then there is Gatsby which is all React. (Listen to our latest ShopTalk Show as we discuss it.) Gridsome seems like the most 1-to-1 comparison in Vue-land, the notable comparison being how they both are designed to suck in data from any source. Components though, of course. I’m not sure there is a flagship Angular-based static site generator, but they are out there, and Angular is components all the way down.

Components are so ubiquitous that perhaps you don’t even think about it anymore. But you might feel it, particularly if you jump back and forth between projects that aren’t component-driven. WordPress development, generally, I feel, isn’t component driven. Sure, you’ve got your header.php and footer.php files and such. You can break those apart however you want, but it’s rather ad-hoc. You aren’t explicitly building components and feeding those components local data and testing them as such. (You can get a lot closer with something like Timber.)

Building front-ends out of server-side code is absolutely fine. Server-side rendering is rife with advantages. But server-side languages don’t seem to have embraced components the way JavaScript has. And since everyone seems to like components (front-end devs obviously love it, designers think that way anyway, back-end devs understand it…) it’s no surprise to me to see this surge of beloved projects build server-side (or build-time) generated sites from JavaScript, simply because it’s component-based and components are just a good idea.

The post Components, yo. appeared first on CSS-Tricks.

CSS-Tricks

[Top]

Iterating a React Design with Styled Components

In a perfect world, our projects would have unlimited resources and time. Our teams would begin coding with well thought out and highly refined UX designs. There would be consensus among developers about the best way to approach styling. There’d be one or more CSS gurus on the team who could ensure that functionality and style could roll out simultaneously without it turning into a train-wreck.

I’ve actually seen this happen in large enterprise environments. It’s a beautiful thing. This article is not for those people.

On the flip side of the coin is the tiny startup that has zero funding, one or two front-end developers, and a very short timeline to demonstrate some functionality. It doesn’t have to look perfect, but it should at least render reasonably well on desktop, tablet, and mobile. This gets them to a point where it can be shown to advisors and early users; maybe even potential investors who’ve expressed an interest in the concept. Once they get some cashflow from sales and/or investment, they can get a dedicated UX designer and polish the interface.

What follows is for this latter group.

Project Kickoff Meeting

Let’s invent a company to get the ball rolling.

Solar Excursions is a small travel agency aiming to serve the near-future’s burgeoning space tourism industry.

Our tiny development team has agreed that React will be used for the UI. One of our front-end developers is big on Sass, and the other is enamored with CSS in JavaScript. But they’ll be hard pressed to knock out their initial sprint goals; there’s certainly no time for arguing about the best possible styling approach. Both coders agree the choice doesn’t matter much in the long run, as long as its consistently executed. They’re certain that implementing the styling from scratch under the gun now will incur technical debt that will have to be cleaned up later.

After some discussion, the team opts to plan for one or more “styling refactor” sprints. For now, we’ll just focus on getting something up on the screen using React-Bootstrap. That way we’ll be able to quickly build working desktop and mobile layouts without much fuss.

The less time spent on front-end styling the better, because we’ll also need the UI to hook up to the services our backend developer will be cranking out. And, as our application architecture begins to take shape, both front-enders agree it’s important that it be unit tested. They have a lot on their plate.

Based on my discussions with the Powers That Be, as a dedicated project manager, I slaved over Balsamiq for at least ten minutes to provide the team with mockups for the booking page on desktop and mobile. I assume they’ll make tablet meet in the middle and look reasonable.

A desktop and mobile mockup of the proposed layout for the page, side by side with the desktop mockup on the left. Both mockups use rough black and white layouts of the various components for the screen.
Initial mockups for the Solar Excursions Trip Booking Page on desktop (left) and mobile (right).

Sprint Zero: Review Meeting

Pizza all around! The team worked really hard to hit its goals, and we now have a booking page with a layout that approximates the mockups. The infrastructure for services is coming together, but there’s quite a way to go before we can connect the UI to it. In the interim, the front-enders are using a hardcoded mock data structure.

Screenshots of the page after the first round of development on desktop (left) and mobile (right). Both are approximately the same as the earlier mockups with most components looking exactly like the default user interface provided by the Bootstrap framework.
The first iteration of the page in code using react-bootstrap.

Here’s a look at our UI code so far:

This is all straightforward React. We’re using some of that Hooks hotness, but it’s probably passé to most of you by now.

The key takeaway to notice here is how four of our five application components import and use components from react-bootstrap. Only the main App component is unaffected. That’s because it just composes the top level view with our custom components.

// App.js imports import React, { useState } from "react"; import Navigation from "./Navigation"; import Page from "./Page";  // Navigation.js imports import React from "react"; import { Navbar, Dropdown, Nav } from "react-bootstrap";  // Page.js imports import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { Container, Row, Col } from "react-bootstrap";  // PosterCarousel.js imports import React from "react"; import { Alert, Carousel, Image } from "react-bootstrap";  // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import {   Button,   Card,   Col,   Container,   Dropdown,   Jumbotron,   ListGroup,   Row,   ToggleButtonGroup,   ToggleButton } from "react-bootstrap";

The decision to move fast with Bootstrap has allowed us to hit our sprint goals, but we’re already accumulating technical debt. This is just four affected components, but as the application grows, it’s clear the “styling refactor” sprints that we planned for are going to become exponentially harder. And we haven’t even customized these components much. Once we have tens of components, all using Bootstrap with lots of inline styling to pretty them up, refactoring them to remove react-bootstrap dependencies will be a scary proposition indeed.

Rather than building more of the booking pipeline pages, the team decides that we’ll spend the next sprint working to isolate the react-bootstrap usage in a custom component kit since our services are still under construction. Application components will only use components from this kit. That way, when it comes time to ween ourselves from react-bootstrap, the process will be much easier. We won’t have to refactor thirty usages of the react-bootstrap Button throughout the app, we’ll just rewrite the internals of our KitButton component.

Sprint One: Review Meeting

Well, that was easy. High-fives. No change to the visual appearance of the UI, but we now have a “kit” folder that’s sibling to “components” in our React source. It has a bunch of files like KitButton.js, which basically export renamed react-bootstrap components.

An example component from our kit looks like this:

// KitButton.js import { Button, ToggleButton, ToggleButtonGroup } from "react-bootstrap"; export const KitButton = Button; export const KitToggleButton = ToggleButton; export const KitToggleButtonGroup = ToggleButtonGroup;

We wrap those all kit components up into a module like this:

// kit/index.js import { KitCard } from "./KitCard"; import { KitHero } from "./KitHero"; import { KitList } from "./KitList"; import { KitImage } from "./KitImage"; import { KitCarousel } from "./KitCarousel"; import { KitDropdown } from "./KitDropdown"; import { KitAttribution } from "./KitAttribution"; import { KitNavbar, KitNav } from "./KitNavbar"; import { KitContainer, KitRow, KitCol } from "./KitContainer"; import { KitButton, KitToggleButton, KitToggleButtonGroup } from "./KitButton"; export {   KitCard,   KitHero,   KitList,   KitImage,   KitCarousel,   KitDropdown,   KitAttribution,   KitButton,   KitToggleButton,   KitToggleButtonGroup,   KitContainer,   KitRow,   KitCol,   KitNavbar,   KitNav };

And now our application components are completely free of react-bootstrap. Here are the imports for the affected components:

// Navigation.js imports import React from "react"; import { KitNavbar, KitNav, KitDropdown } from "../kit";   // Page.js imports  import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { KitContainer, KitRow, KitCol } from "../kit";   // PosterCarousel.js imports import React from "react"; import { KitAttribution, KitImage, KitCarousel } from "../kit";   // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import {   KitCard,   KitHero,   KitList,   KitButton,   KitToggleButton,   KitToggleButtonGroup,   KitDropdown,   KitContainer,   KitRow,   KitCol } from "../kit";

Here’s the front-end codebase now:

Although we’ve corralled all of the react imports into our kit components, our application components still rely a bit on the react-bootstrap implementation because the attributes we place on our kit component instances are the same as those of react-bootstrap. That constrains us when it comes to re-implementing the kit components, because we need to adhere to the same API. For instance:

// From Navigation.js <KitNavbar bg="dark" variant="dark" fixed="top">

Ideally, we wouldn’t have to add those react-bootstrap specific attributes when we instantiate our KitNavbar.

The front-enders promise to refactor those out as we go, now that we’ve identified them as problematic. And any new references to react-bootstrap components will go into our kit instead of directly into the application components.

Meanwhile, we’ve shared our mock data with the server engineer, who is working hard to build separate server environments, implement the database schema, and expose some services to us.

That gives us time to add some gloss to our UI in the next sprint — which is good because the Powers That Be would like to see separate themes for each destination. As the user browses destinations, we need to have the UI color scheme change to match the displayed travel poster. Also, we want to try and spiff up those components a bit to begin evolving our own look and feel. Once we have some money coming in, we’ll get a designer to do a complete overhaul, but hopefully we can reach a happy medium for our early users.

Sprint Two: Review Meeting

Wow! The team really pulled out all the stops this sprint. We got per-destination themes, customized components, and a lot of the lingering react-bootstrap API implementations removed from the application components.

Here’s what the desktop looks like now:

A more complete rendering of the landing page, this time using Mars as an example to show off a bright orange and red color theme. The interface components no longer look like they came directly from Bootstrap, but are still minimal in style, like dropdowns, buttons and text.
Check out the solarized theme for the red planet!

In order to pull this off, the front-enders brought in the Styled Components library. It made styling the individual kit components a breeze, as well as adding support for multiple themes.

Let’s look at a few highlights of their changes for this sprint.

First, for global things like pulling in fonts and setting the page body styles, we have a new kit component called KitGlobal.

// KitGlobal.js import { createGlobalStyle } from "styled-components"; export const KitGlobal = createGlobalStyle`   body {     @import url('https://fonts.googleapis.com/css?family=Orbitron:500|Nunito:600|Alegreya+Sans+SC:700');     background-color: $ {props => props.theme.foreground};     overflow-x: hidden;   } `;

It uses the createGlobalStyle helper to define the CSS for the body element. That imports our desired web fonts from Google, sets the background color to whatever the current theme’s “foreground” value is, and turns off overflow in the x-direction to eliminate a pesky horizontal scrollbar. We use that KitGlobal component in the render method of our App component.

Also in the App component, we import ThemeProvider from styled-components, and something called “themes” from ../theme. We use React’s useState to set the initial theme to themes.luna and React’s useEffect to call setTheme whenever the “destination” changes. The returned component is now wrapped in ThemeProvider, which is passed “theme” as a prop. Here’s the App component in its entirety.

// App.js import React, { useState, useEffect } from "react"; import { ThemeProvider } from "styled-components"; import themes from "../theme/"; import { KitGlobal } from "../kit"; import Navigation from "./Navigation"; import Page from "./Page"; export default function App(props) {   const [destinationIndex, setDestinationIndex] = useState(0);   const [theme, setTheme] = useState(themes.luna);   const destination = props.destinations[destinationIndex];   useEffect(() => {     setTheme(themes[destination.theme]);   }, [destination]);    return (     <ThemeProvider theme={theme}>       <React.Fragment>         <KitGlobal />         <Navigation           {...props}           destinationIndex={destinationIndex}           setDestinationIndex={setDestinationIndex}         />         <Page           {...props}           destinationIndex={destinationIndex}           setDestinationIndex={setDestinationIndex}         />       </React.Fragment>     </ThemeProvider>   ); }

KitGlobal is rendering like any other component. Nothing special there, only that the body tag is affected. ThemeProvider is using the React Context API to pass theme down to whatever components need it (which is all of them). In order to fully understand that, we also need to take a look at what a theme actually is.

To create a theme, one of our front-enders took all the travel posters and created palettes for each by extracting the prominent colors. That was fairly simple.

A screenshot of the Tiny Eye website showing the red color palette used for the Mars page theme. There are two images on the left from the page that Tiny Eye used to create a color palette in the center containing various shades of red and the hex values for them on the right.
We used TinyEye for this.

Obviously, we weren’t going to use all the colors. The approach was mainly to dub the most used two colors foreground and background. Then we took three more colors, generally ordered from lightest to darkest as accent1, accent2, and accent3. Finally, we picked two contrasting colors to call text1 and text2. For the above destination, that looked like:

// theme/index.js (partial list) const themes = {   ...   mars: {     background: "#a53237",     foreground: "#f66f40",     accent1: "#f8986d",     accent2: "#9c4952",     accent3: "#f66f40",     text1: "#f5e5e1",     text2: "#354f55"   },   ... }; export default themes;

Once we have a theme for each destination, and it is being passed into all the components (including the kit components that our application components are now built from), we need to use styled-components to apply those theme colors as well as our custom visual styling, like the panel corners and “border glow.”

This is a simple example where we made our KitHero component apply the theme and custom styles to the Bootstrap Jumbotron:

// KitHero.js import styled from "styled-components"; import { Jumbotron } from "react-bootstrap";  export const KitHero = styled(Jumbotron)`   background-color: $ {props => props.theme.accent1};   color: $ {props => props.theme.text2};   border-radius: 7px 25px;   border-color: $ {props => props.theme.accent3};   border-style: solid;   border-width: 1px;   box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d;   font-family: "Nunito", sans-serif;   margin-bottom: 20px; `;

In this case, we’re good to go with what gets returned from styled-components, so we just name it KitHero and export it.

When we use it in the application, it looks like this:

// DestinationLayout.js (partial code) const renderHero = () => {   return (     <KitHero>       <h2>{destination.header}</h2>       <p>{destination.blurb}</p>       <KitButton>Book Your Trip Now!</KitButton>     </KitHero>   ); };

Then there are more complex cases where we want to preset some attributes on the react-bootstrap component. For instance, the KitNavbar component which we identified earlier as having a bunch of react-bootstrap attributes that we’d rather not pass from the application’s declaration of the component.

Now for a look at how that was handled:

// KitNavbar.js (partial code) import React, { Component } from "react"; import styled from "styled-components"; import { Navbar } from "react-bootstrap";  const StyledBootstrapNavbar = styled(Navbar)`   background-color: $ {props => props.theme.background};   box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d;   display: flex;   flex-direction: horizontal;   justify-content: space-between;   font-family: "Nunito", sans-serif; `;  export class KitNavbar extends Component {   render() {     const { ...props } = this.props;     return <StyledBootstrapNavbar fixed="top" {...props} />;   } }

First, we create a component called StyledBootstrapNavbar using styled-components. We were able to handle some of the attributes with the CSS we passed to styled-components. But in order to continue leveraging (for now) the reliable stickiness of the component to the top of the screen while everything else is scrolled, our front-enders elected to continue using react-bootstrap’s fixed attribute. In order to do that, we had to create a KitNavbar component that rendered an instance of StyledBootstrapNavbar with the fixed=top attribute. We also passed through all the props, which includes its children.

We only have to create a separate class that renders styled-component’s work and passes props through to it if we want to explicitly set some attributes in our kit component by default. In most cases, we can just name and return styled-component’s output and use it as we did with KitHero above.

Now, when we render the KitNavbar in our application’s Navigation component, it looks like this:

// Navigation.js (partial code) return (   <KitNavbar>     <KitNavbarBrand>       <KitLogo />       Solar Excursions     </KitNavbarBrand>     {renderDestinationMenu()}   </KitNavbar> );

Finally, we took our first stabs at refactoring our kit components away from react-bootstrap. The KitAttribution component is a Bootstrap Alert which, for our purposes, is little more than an ordinary div. We were able to easily refactor to remove its dependency on react-bootstrap.

This is the component as it emerged from the previous sprint:

// KitAttribution.js (using react-bootstrap) import { Alert } from "react-bootstrap"; export const KitAttribution = Alert;

This is what it looks like now:

// KitAttribution.js import styled from "styled-components"; export const KitAttribution = styled.div`   text-align: center;   background-color: $ {props => props.theme.accent1};   color: $ {props => props.theme.text2};   border-radius: 7px 25px;   border-color: $ {props => props.theme.accent3};   border-style: solid;   border-width: 1px;   box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d;   font-family: "Alegreya Sans SC", sans-serif;   > a {     color: $ {props => props.theme.text2};     font-family: "Nunito", sans-serif;   }   > a:hover {     color: $ {props => props.theme.background};     text-decoration-color: $ {props => props.theme.accent3};   } `;

Notice how we no longer import react-bootstrap and we use styled.div as the component base. They won’t all be so easy, but it’s a process.

Here are the results of our team’s styling and theming efforts in sprint 3:

Conclusion

After three sprints, our team is well on its way to having a scalable component architecture in place for the UI.

  • We are moving quickly thanks to react-bootstrap, but are no longer piling up loads of technical debt as a result of it.
  • Thanks to styled-components, we were able to implement multiple themes (like how almost every app on the Internet these days sports dark and light modes). We also don’t look like an out-of-the-box Bootstrap app anymore.
  • By implementing a custom component kit that contains all references to react-bootstrap, we can refactor away from it as time permits.

The post Iterating a React Design with Styled Components appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Making Web Components for Different Contexts

This article isn’t about how to build web components. Caleb Williams already wrote a comprehensive guide about that recently. Let’s talk about how to work with them, what to consider when making them, and how to embrace them in your projects.

If you are new to web components, Caleb’s guide is a great read, but here are more resources that will get you up to speed:

Since web components are now widely supported (thanks to the hard work of many people behind the scenes) — and considering the imminent switch that Edge will make to the chromium platform — people are now thinking about web components as “native” and a platform-compliant way to build reusable UI components to keep consistency across design systems and web projects, while using the power of the Shadow DOM to encapsulate style and logics inside the component itself.

Well, this can be true and false at the same time. But first, let’s get acquainted with the Abstraction Layers Triangle.

The Abstraction Layers Triangle

Technically, we should consider web components as an extension of our favorite markup language, HTML (yep!). The Web Components API allows us to create custom HTML elements (e.g. <foo-bar>) that don’t exist in HTML.

We are told web components are basically new HTML elements, so we should consider them as part of the HTML specifications and, consequently, we should follow its paradigms, core concepts, and utilization. If we assume all of these points, we will figure out that our components will live among the lowest levels of the web platform stack, alongside HTML, CSS, and JavaScript.

Frameworks and libraries like React, Vue, Angular, SvelteJS work on their abstraction level, right above other tools that live in a sort of “middle earth,” like StencilJs, Hybrids and Lit. Under these layers of abstraction, we can find our basic web technologies… and vanilla web components. We can represent this concept with an ALT (A>bstraction L Triangle) diagram:

The higher we go, the more abstraction things get.

Why is this important? Well, it helps us visualize the various layers that exist on top of native components and understand the context they are used so that they can be built for an intended context. What’s context? That’s where we’re headed.

Same technology, different contexts

The Shadow DOM is a key factor in the Web Components API. It allows us to bundle JavaScript and CSS inside a custom element to both prevent external interferences and style manipulations, unless we expressly allow it. There are indeed some approaches that developers can follow to allow external CSS to leak into the shadow root and into a component, including custom properties and the ::part and ::theme pseudo-elements, which is something Monica Dinculescu) has covered so well.

There is also another thing to consider: the context we are working with. After three years of building web components personally, I can identify two contexts: the private context (like a design system) and the standard context (like plain HTML, CSS, and JavaScript without custom styles).

Before designing components, we need to know how they will be used, so determining the type of context is a key to all of this. The most easy way is targeting only one context, but with a small CSS trick. we can build our components for both of them.

Let’s look at the differences between the two contexts before we get into that.

Private context

A private context is a closed ecosystem that provides components with their own style that must be used as-is. So, if we are building a component library that comes from specific styling guidelines or a design system, each component will reflect custom styles so there’s no need to code them up each time they’re needed.

That can be true also with JavaScript logic. For example, we can attach a closed shadow root that prevent others to accidentally pierce the shadow boundary with a querySelector. As a a result, we can simply pick and use all any component, avoiding issues like style inconsistencies and CSS collisions. As the author, you can also get to define a set of CSS custom properties (or ::parts) that can be used to style a component for a specific use case, but this is not the focus point of a design system.

Here’s an example of a web component component in a private context. It has all of the styles and logic contained inside its shadow-root and and can simply be dropped into any page.

See the Pen
Closed Context Web Component
by Mattia Astorino (@equinusocio)
on CodePen.

This example and the one to follow are for demonstration purposes and not intended for production use because they do not make considerations for key situations, like accessibility and other optimizations.

Components in a private context can be rarely used outside of that context. For example, if we try to take an element from a design system (which has its own enforced styles), we’re unable to simply add it to a project and expect to customize it. You know how Bootstrap can be themed and customized to your liking? This is pretty much the opposite of that. These components are made to live inside their context and their context only.

Standard context

A standard context may be the most complex type of component, not only because the environment can range anywhere from a full-fledged framework (like Vue and React) to plain vanilla HTML, but also because everyone should be able to use that component like any other element.

For example, when adding a component publicly, say to npm, those who use it will expect to be able to customize it, at least to some degree.

Do you know of any HTML element that comes with its own presentational style? The answer should be no because, well, elements must be explicitly styled with CSS. This is also true for web components made in a standard context. A single web component should be customizable by adding classes an attributes, or other methods.

Here’s the same <todo-list> element that we saw in the closed context example, but designed for a standard context. It works as-is, without any presentational styles inside its shadow root. In fact, it only contains the required logic and baseline CSS to make sure it functions. Otherwise, it’s completely customizable like any standard HTML element, like a div.

See the Pen
Standard Context Web Component
by Mattia Astorino (@equinusocio)
on CodePen.

Both of the examples we’ve looked at for each context are made with the same component. The difference is that the component in a standard context an be customized and selected with external CSS.

Web components and composition

OK, so working with web components is really the same as working with plain HTML, though as we’ve seen, it’s important to follow the paradigms and principles of the given content. Well, thing we need to be mindful of is the web component composition.

As explained by Google Web Fundamentals:

Composition is one of the least understood features of shadow DOM, but it’s arguably the most important.

In our world of web development, composition is how we construct apps, declaratively out of HTML. Different building blocks (<div>s, <header>s, <form>s, <input>s) come together to form apps. Some of these tags even work with each other. Composition is why native elements like <select>, <details>, <form>, and <video> are so flexible. Each of those tags accepts certain HTML as children and does something special with them. For example, <select> knows how to render option> and <optgroup> into dropdown and multi-select widgets. The <details> element renders <summary> as an expandable arrow. Even <video> knows how to deal with certain children: <source> elements don’t get rendered, but they do affect the video’s behavior. What magic!

Composition is what we normally do when we work with HTML. Since web components are merely HTML elements with a DOM reference — and not logical containers — we should rely on composition to build our components and any sub-components. If you think about the ul and and select you will notice that you declaratively compose these elements to get the final output and you have specific attributes to be used with the main component (e.g. [readonly]) or the sub-component (e.g. [selected]). This is true also for web components, and if you are building a custom list, consider to build the main component (<custom-list>) and the child one (<custom-li>). Using the [slot] element, you can define where children elements will be placed and also placeholder content that will be shown when no children are passed through.

Web components and accessibility

Another thing to consider is that “small” topic we call accessibility. Since we are creating completely new HTML elements, we need to consider the accessibility of our elements in order to provide a basic semantic role, any keyboard navigation as well as the user’s operating system preferences, like the reduce motion and high contrast settings.

I strongly suggest the following resources as reference for building accessible and inclusive components, how to define semantic markup, and how to implement a basic keyboard navigation.

Conclusion

Web components are an emerging technology in web development and, as such, there really aren’t any clearly defined best practices to guide us as far as building them for their intended or maximized use. When you find yourself working with them, perhaps the single thing you can take away from this post is to consider whether they are intended for a closed context or a standard context, then ask yourself WHI:

  • Who will use this component?
  • How much flexibility should that person have to customize it?
  • Is this component for everyone or for a specific audience?

The post Making Web Components for Different Contexts appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Advanced Tooling for Web Components

Over the course of the last four articles in this five-part series, we’ve taken a broad look at the technologies that make up the Web Components standards. First, we looked at how to create HTML templates that could be consumed at a later time. Second, we dove into creating our own custom element. After that, we encapsulated our element’s styles and selectors into the shadow DOM, so that our element is entirely self-contained.

We’ve explored how powerful these tools can be by creating our own custom modal dialog, an element that can be used in most modern application contexts regardless of the underlying framework or library. In this article, we will look at how to consume our element in the various frameworks and look at some advanced tooling to really ramp up your Web Component skills.

Article Series:

  1. An Introduction to Web Components
  2. Crafting Reusable HTML Templates
  3. Creating a Custom Element from Scratch
  4. Encapsulating Style and Structure with Shadow DOM
  5. Advanced Tooling for Web Components (This post)

Framework agnostic

Our dialog component works great in almost any framework or even without one. (Granted, if JavaScript is disabled, the whole thing is for naught.) Angular and Vue treat Web Components as first-class citizens: the frameworks have been designed with web standards in mind. React is slightly more opinionated, but not impossible to integrate.

Angular

First, let’s take a look at how Angular handles custom elements. By default, Angular will throw a template error whenever it encounters an element it doesn’t recognize (i.e. the default browser elements or any of the components defined by Angular). This behavior can be changed by including the CUSTOM_ELEMENTS_SCHEMA.

…allows an NgModule to contain the following:

  • Non-Angular elements named with dash case (-).
  • Element properties named with dash case (-). Dash case is the naming convention for custom elements.

Angular Documentation

Consuming this schema is as simple as adding it to a module:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';  @NgModule({   /** Omitted */   schemas: [ CUSTOM_ELEMENTS_SCHEMA ] }) export class MyModuleAllowsCustomElements {}

That’s it. After this, Angular will allow us to use our custom element wherever we want with the standard property and event bindings:

<one-dialog [open]="isDialogOpen" (dialog-closed)="dialogClosed($  event)">   <span slot="heading">Heading text</span>   <div>     <p>Body copy</p>   </div> </one-dialog>

Vue

Vue’s compatibility with Web Components is even better than Angular’s as it doesn’t require any special configuration. Once an element is registered, it can be used with Vue’s default templating syntax:

<one-dialog v-bind:open="isDialogOpen" v-on:dialog-closed="dialogClosed">   <span slot="heading">Heading text</span>   <div>     <p>Body copy</p>   </div> </one-dialog>

One caveat with Angular and Vue, however, is their default form controls. If we wish to use something like reactive forms or [(ng-model)] in Angular or v-model in Vue on a custom element with a form control, we will need to set up that plumbing for which is beyond the scope of this article.

React

React is slightly more complicated than Angular. React’s virtual DOM effectively takes a JSX tree and renders it as a large object. So, instead of directly modifying attributes on HTML elements like Angular or Vue, React uses an object syntax to track changes that need to be made to the DOM and updates them in bulk. This works just fine in most cases. Our dialog’s open attribute is bound to its property and will respond perfectly well to changing props.

The catch comes when we start to look at the CustomEvent dispatched when our dialog closes. React implements a series of native event listeners for us with their synthetic event system. Unfortunately, that means that controls like onDialogClosed won’t actually attach event listeners to our component, so we have to find some other way.

The most obvious means of adding custom event listeners in React is by using DOM refs. In this model, we can reference our HTML node directly. The syntax is a bit verbose, but works great:

import React, { Component, createRef } from 'react';  export default class MyComponent extends Component {   constructor(props) {     super(props);     // Create the ref     this.dialog = createRef();     // Bind our method to the instance     this.onDialogClosed = this.onDialogClosed.bind(this);      this.state = {       open: false     };   }    componentDidMount() {     // Once the component mounds, add the event listener     this.dialog.current.addEventListener('dialog-closed', this.onDialogClosed);   }    componentWillUnmount() {     // When the component unmounts, remove the listener     this.dialog.current.removeEventListener('dialog-closed', this.onDialogClosed);   }    onDialogClosed(event) { /** Omitted **/ }    render() {     return <div>       <one-dialog open={this.state.open} ref={this.dialog}>         <span slot="heading">Heading text</span>         <div>           <p>Body copy</p>         </div>       </one-dialog>     </div>   } }

Or, we can use stateless functional components and hooks:

import React, { useState, useEffect, useRef } from 'react';  export default function MyComponent(props) {   const [ dialogOpen, setDialogOpen ] = useState(false);   const oneDialog = useRef(null);   const onDialogClosed = event => console.log(event);    useEffect(() => {     oneDialog.current.addEventListener('dialog-closed', onDialogClosed);     return () => oneDialog.current.removeEventListener('dialog-closed', onDialogClosed)   });    return <div>       <button onClick={() => setDialogOpen(true)}>Open dialog</button>       <one-dialog ref={oneDialog} open={dialogOpen}>         <span slot="heading">Heading text</span>         <div>           <p>Body copy</p>         </div>       </one-dialog>     </div> }

That’s not bad, but you can see how reusing this component could quickly become cumbersome. Luckily, we can export a default React component that wraps our custom element using the same tools.

import React, { Component, createRef } from 'react'; import PropTypes from 'prop-types';  export default class OneDialog extends Component {   constructor(props) {     super(props);     // Create the ref     this.dialog = createRef();     // Bind our method to the instance     this.onDialogClosed = this.onDialogClosed.bind(this);   }    componentDidMount() {     // Once the component mounds, add the event listener     this.dialog.current.addEventListener('dialog-closed', this.onDialogClosed);   }    componentWillUnmount() {     // When the component unmounts, remove the listener     this.dialog.current.removeEventListener('dialog-closed', this.onDialogClosed);   }    onDialogClosed(event) {     // Check to make sure the prop is present before calling it     if (this.props.onDialogClosed) {       this.props.onDialogClosed(event);     }   }    render() {     const { children, onDialogClosed, ...props } = this.props;     return <one-dialog {...props} ref={this.dialog}>       {children}     </one-dialog>   } }  OneDialog.propTypes = {   children: children: PropTypes.oneOfType([       PropTypes.arrayOf(PropTypes.node),       PropTypes.node   ]).isRequired,   onDialogClosed: PropTypes.func };

…or again as a stateless, functional component:

import React, { useRef, useEffect } from 'react'; import PropTypes from 'prop-types';  export default function OneDialog(props) {   const { children, onDialogClosed, ...restProps } = props;   const oneDialog = useRef(null);      useEffect(() => {     onDialogClosed ? oneDialog.current.addEventListener('dialog-closed', onDialogClosed) : null;     return () => {       onDialogClosed ? oneDialog.current.removeEventListener('dialog-closed', onDialogClosed) : null;       };   });    return <one-dialog ref={oneDialog} {...restProps}>{children}</one-dialog> }

Now we can use our dialog natively in React, but still keep the same API across all our applications (and still drop classes, if that’s your thing).

import React, { useState } from 'react'; import OneDialog from './OneDialog';  export default function MyComponent(props) {   const [open, setOpen] = useState(false);   return <div>     <button onClick={() => setOpen(true)}>Open dialog</button>     <OneDialog open={open} onDialogClosed={() => setOpen(false)}>       <span slot="heading">Heading text</span>       <div>         <p>Body copy</p>       </div>     </OneDialog>   </div> }

Advanced tooling

There are a number of great tools for authoring your own custom elements. Searching through npm reveals a multitude of tools for creating highly-reactive custom elements (including my own pet project), but the most popular today by far is lit-html from the Polymer team and, more specifically for Web Components, LitElement.

LitElement is a custom elements base class that provides a series of APIs for doing all of the things we’ve walked through so far. It can be run in a browser without a build step, but if you enjoy using future-facing tools like decorators, there are utilities for that as well.

Before diving into how to use lit or LitElement, take a minute to familiarize yourself with tagged template literals, which are a special kind of function called on template literal strings in JavaScript. These functions take in an array of strings and a collection of interpolated values and can return anything you might want.

function tag(strings, ...values) {   console.log({ strings, values });   return true; } const who = 'world';  tag`hello $  {who}`;  /** would log out { strings: ['hello ', ''], values: ['world'] } and return true **/

What LitElement gives us is live, dynamic updating of anything passed to that values array, so as a property updates, the element’s render function would be called and the resulting DOM would be re-rendered

import { LitElement, html } from 'lit-element';  class SomeComponent {   static get properties() {     return {        now: { type: String }     };   }    connectedCallback() {     // Be sure to call the super     super.connectedCallback();     this.interval = window.setInterval(() => {       this.now = Date.now();     });   }    disconnectedCallback() {     super.disconnectedCallback();     window.clearInterval(this.interval);   }    render() {     return html`<h1>It is $  {this.now}</h1>`;   } }  customElements.define('some-component', SomeComponent);

See the Pen
LitElement now example
by Caleb Williams (@calebdwilliams)
on CodePen.

What you will notice is that we have to define any property we want LitElement to watch using the static properties getter. Using that API tells the base class to call render whenever a change is made to the component’s properties. render, in turn, will update only the nodes that need to change.

So, for our dialog example, it would look like this using LitElement:

See the Pen
Dialog example using LitElement
by Caleb Williams (@calebdwilliams)
on CodePen.

There are several variants of lit-html available, including Haunted, a React hooks-style library for Web Components that can also make use of virtual components using lit-html as a base.

At the end of the day, most of the modern Web Components tools are various flavors of what LitElement is: a base class that abstracts common logic away from our components. Among the other flavors are Stencil, SkateJS, Angular Elements and Polymer.

What’s next

Web Components standards are continuing to evolve and new features are being discussed and added to browsers on an ongoing basis. Soon, Web Component authors will have APIs for interacting with web forms at a high level (including other element internals that are beyond the scope of these introductory articles), like native HTML and CSS module imports, native template instantiation and updating controls, and many more which can be tracked on the W3C/web components issues board on GitHub.

These standards are ready to adopt into our projects today with the appropriate polyfills for legacy browsers and Edge. And while they may not replace your framework of choice, they can be used alongside them to augment you and your organization’s workflows.

The post Advanced Tooling for Web Components appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

An Introduction to Web Components

Front-end development moves at a break-neck pace. This is made evident by the myriad articles, tutorials, and Twitter threads bemoaning the state of what once was a fairly simple tech stack. In this article, I’ll discuss why Web Components are a great tool to deliver high-quality user experiences without complicated frameworks or build steps and that don’t run the risk of becoming obsolete. In subsequent articles of this five-part series, we will dive deeper into each of the specifications.

This series assumes a basic understanding of HTML, CSS, and JavaScript. If you feel weak in one of those areas, don’t worry, building a custom element actually simplifies many complexities in front-end development.

Article Series:

  1. An Introduction to Web Components (This post)
  2. Crafting Reusable HTML Templates (Coming soon!)
  3. Creating a Custom Element from Scratch (Coming soon!)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

What are Web Components, anyway?

Web Components consist of three separate technologies that are used together:

  1. Custom Elements. Quite simply, these are fully-valid HTML elements with custom templates, behaviors and tag names (e.g. <one-dialog>) made with a set of JavaScript APIs. Custom Elements are defined in the HTML Living Standard specification.
  2. Shadow DOM. Capable of isolating CSS and JavaScript, almost like an <iframe>. This is defined in the Living Standard DOM specification.
  3. HTML templates. User-defined templates in HTML that aren’t rendered until called upon. The <template> tag is defined in the HTML Living Standard specification.

These are what make up the Web Components specification.

HTML Imports is likely to be the fourth technology in the stack, but it has yet to be implemented in any of the big four browsers. The Chrome team has announced it an intent to implement them in a future release.

Web Components are generally available in all of the major browsers with the exception of Microsoft Edge and Internet Explorer 11, but polyfills exist to fill in those gaps.

Referring to any of these as Web Components is technically accurate because the term itself is a bit overloaded. As a result, each of the technologies can be used independently or combined with any of the others. In other words, they are not mutually exclusive.

Let’s take a quick look at each of those first three. We’ll dive deeper into them in other articles in this series.

Custom elements

As the name implies, custom elements are HTML elements, like <div>, <section> or <article>, but something we can name ourselves that are defined via a browser API. Custom elements are just like those standard HTML elements — names in angle brackets — except they always have a dash in them, like <news-slider> or <bacon-cheeseburger>. Going forward, browser vendors have committed not to create new built-in elements containing a dash in their names to prevent conflicts.

Custom elements contain their own semantics, behaviors, markup and can be shared across frameworks and browsers.

class MyComponent extends HTMLElement {   connectedCallback() {     this.innerHTML = `<h1>Hello world</h1>`;   } }      customElements.define('my-component', MyComponent);

See the Pen
Custom elements demo
by Caleb Williams (@calebdwilliams)
on CodePen.

In this example, we define <my-component>, our very own HTML element. Admittedly, it doesn’t do much, however this is the basic building block of a custom element. All custom elements must in some way extend an HTMLElement in order to be registered with the browser.

Custom elements exist without third-party frameworks and the browser vendors are dedicated to the continued backward compatibility of the spec, all but guaranteeing that components written according to the specifications will not suffer from breaking API changes. What’s more, these components can generally be used out-of-the-box with today’s most popular frameworks, including Angular, React, Vue, and others with minimal effort.

Shadow DOM

The shadow DOM is an encapsulated version of the DOM. This allows authors to effectively isolate DOM fragments from one another, including anything that could be used as a CSS selector and the styles associated with them. Generally, any content inside of the document’s scope is referred to as the light DOM, and anything inside a shadow root is referred to as the shadow DOM.

When using the light DOM, an element can be selected by using document.querySelector('selector') or by targeting any element’s children by using element.querySelector('selector'); in the same way, a shadow root’s children can be targeted by calling shadowRoot.querySelector where shadowRoot is a reference to the document fragment — the difference being that the shadow root’s children will not be select-able from the light DOM. For example, If we have a shadow root with a <button> inside of it, calling shadowRoot.querySelector('button') would return our button, but no invocation of the document’s query selector will return that element because it belongs to a different DocumentOrShadowRoot instance. Style selectors work in the same way.

In this respect, the shadow DOM works sort of like an <iframe> where the content is cut off from the rest of the document; however, when we create a shadow root, we still have total control over that part of our page, but scoped to a context. This is what we call encapsulation.

If you’ve ever written a component that reuses the same id or relies on either CSS-in-JS tools or CSS naming strategies (like BEM), shadow DOM has the potential to improve your developer experience.

Imagine the following scenario:

<div>   <div id="example">     <!-- Pseudo-code used to designate a shadow root -->     <#shadow-root>       <style>       button {         background: tomato;         color: white;       }       </style>       <button id="button">This will use the CSS background tomato</button>     </#shadow-root>   </div>   <button id="button">Not tomato</button> </div>

Aside from the pseudo-code of <#shadow-root> (which is used here to demarcate the shadow boundary which has no HTML element), the HTML is fully valid. To attach a shadow root to the node above, we would run something like:

const shadowRoot = document.getElementById('example').attachShadow({ mode: 'open' }); shadowRoot.innerHTML = `<style> button {   color: tomato; } </style> <button id="button">This will use the CSS color tomato <slot></slot></button>`;

A shadow root can also include content from its containing document by using the <slot> element. Using a slot will drop user content from the outer document at a designated spot in your shadow root.

See the Pen
Shadow DOM style encapsulation demo
by Caleb Williams (@calebdwilliams)
on CodePen.

HTML templates

The aptly-named HTML <template> element allows us to stamp out re-usable templates of code inside a normal HTML flow that won’t be immediately rendered, but can be used at a later time.

<template id="book-template">   <li><span class="title"></span> &mdash; <span class="author"></span></li> </template>  <ul id="books"></ul>

The example above wouldn’t render any content until a script has consumed the template, instantiated the code and told the browser what to do with it.

const fragment = document.getElementById('book-template'); const books = [   { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },   { title: 'A Farewell to Arms', author: 'Ernest Hemingway' },   { title: 'Catch 22', author: 'Joseph Heller' } ];  books.forEach(book => {   // Create an instance of the template content   const instance = document.importNode(fragment.content, true);   // Add relevant content to the template   instance.querySelector('.title').innerHTML = book.title;   instance.querySelector('.author').innerHTML = book.author;   // Append the instance ot the DOM   document.getElementById('books').appendChild(instance); });

Notice that this example creates a template (<template id="book-template">) without any other Web Components technology, illustrating again that the three technologies in the stack can be used independently or collectively.

Ostensibly, the consumer of a service that utilizes the template API could write a template of any shape or structure that could be created at a later time. Another page on a site might use the same service, but structure the template this way:

<template id="book-template">   <li><span class="author"></span>'s classic novel <span class="title"></span></li> </template>  <ul id="books"></ul>

See the Pen
Template example
by Caleb Williams (@calebdwilliams)
on CodePen.

That wraps up our introduction to Web Components

As web development continues to become more and more complicated, it will begin to make sense for developers like us to begin deferring more and more development to the web platform itself which has continued to mature. The Web Components specifications are a set of low-level APIs that will continue to grow and evolve as our needs as developers evolve.

In the next article, we will take a deeper look at the HTML templates part of this. Then, we’ll follow that up with a discussion of custom elements and shadow DOM. Finally, we’ll wrap it all up by looking at higher-level tooling and incorporation with today’s popular libraries and frameworks.

Article Series:

  1. An Introduction to Web Components (This post)
  2. Crafting Reusable HTML Templates (Coming soon!)
  3. Creating a Custom Element from Scratch (Coming soon!)
  4. Encapsulating Style and Structure with Shadow DOM (Coming soon!)
  5. Advanced Tooling for Web Components (Coming soon!)

The post An Introduction to Web Components appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

Using React Loadable for Code Splitting by Components and Routes

In a bid to have web applications serve needs for different types of users, it’s likely that more code is required than it would be for one type of user so the app can handle and adapt to different scenarios and use cases, which lead to new features and functionalities. When this happens, it’s reasonable to expect the performance of an app to dwindle as the codebase grows.

Code splitting is a technique where an application only loads the code it needs at the moment, and nothing more. For example, when a user navigates to a homepage, there is probably no need to load the code that powers a backend dashboard. With code splitting, we can ensure that the code for the homepage is the only code that loads, and that the cruft stays out for more optimal loading.

Code splitting is possible in a React application using React Loadable. It provides a higher-order component that can be set up to dynamically import specific components at specific times.

Component splitting

There are situations when we might want to conditionally render a component based on a user event, say when a user logs in to an account. A common way of handling this is to make use of state — the component gets rendered depending on the logged in state of the app. We call this component splitting.

Let’s see how that will look in code.

See the Pen
React-Loadable
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

As a basic example, say we want to conditionally render a component that contains an <h2> heading with “Hello.” Like this:

const Hello = () => { 	return ( 		<React.Fragment> 			<h2>Hello</h2> 		</React.Fragment> 	) }

We can have an openHello state in the App component with an initial value of false. Then we can have a button used to toggle the state, either display the component or hide it. We’ll throw that into a handleHello method, which looks like this:

class App extends React.Component { 	state = { 		openHello: false 	}  	handleHello = () => { 		this.setState({ openHello: !this.state.openHello }) 	} 	render() { 		return ( 			<div className="App"> 				<button onClick={this.handleHello}> 					Toggle Component 				</button>  				{ 					this.state.openHello ? 						<Hello /> 					: null 				} 			</div> 		); 	} }

Take a quick peek in DevTools and take note the Network tab:

Now, let’s refactor to make use of LoadableHello. Instead of importing the component straight up, we will do the import using Loadable. We’ll start by installing the react-loadable package:

## yarn, npm or however you roll yarn add react-loadable

Now that’s been added to our project, we need to import it into the app:

import Loadable from 'react-loadable';

We’ll use Loadable to create a “loading” component which will look like this:

const LoadableHello = Loadable({ 	loader: () => import('./Hello'), 	loading() { 		return <div>Loading...</div> 	} })

We pass a function as a value to loader which returns the Hello component we created earlier, and we make use of import() to dynamically import it. The fallback UI we want to render before the component is imported is returned by loading(). In this example, we are returning a div element, though we can also put a component in there instead if we want.

Now, instead of inputting the Hello component directly in the App component, we’ll put LoadableHello to the task so that the conditional statement will look like this:

{ 	this.state.openHello ? 		<LoadableHello /> 	: null }

Check this out — now our Hello component loads into the DOM only when the state is toggled by the button:

And that’s component splitting: the ability to load one component to load another asynchronously!

Route-based splitting

Alright, so we saw how Loadable can be used to load components via other components. Another way to go about it is us ing route-based splitting. The difference here is that components are loaded according to the current route.

So, say a user is on the homepage of an app and clicks onto a Hello view with a route of /hello. The components that belong on that route would be the only ones that load. It’s a fairly common way of handling splitting in many apps and generally works well, especially in less complex applications.

Here’s a basic example of defined routes in an app. In this case, we have two routes: (1) Home (/) and (2) Hello (/hello).

class App extends Component { 	render() { 		return ( 			<div className="App"> 				<BrowserRouter> 					<div> 						<Link to="/">Home</Link> 						<Link to="/hello">Hello</Link> 						<Switch> 							<Route exact path="/" component={Home} /> 							<Route path="/hello" component={Hello} /> 						</Switch> 					</div> 				</BrowserRouter> 			</div> 		); 	} }

As it stands, all components will render when a use switches paths, even though we want to render the one Hello component based on that path. Sure, it’s not a huge deal if we’re talking a few components, but it certainly could be as more components are added and the application grows in size.

Using Loadable, we can import only the component we want by creating a loadable component for each:

const LoadableHello = Loadable({ 	loader: () => import('./Hello'), 	loading() { 		return <div>Loading...</div> 	} }) const LoadableHome = Loadable({ 	loader: () => import('./Home'), 	loading() { 		return <div>Loading...</div> 	} }) class App extends Component { 	render() { 		return ( 			<div className="App"> 				<BrowserRouter> 					<div> 						<Link to="/">Home</Link> 						<Link to="/hello">Hello</Link> 						<Switch> 							<Route exact path="/" component={LoadableHome} /> 							<Route path="/hello" component={LoadableHello} /> 						</Switch> 					</div> 				</BrowserRouter> 			</div> 		); 	} }

Now, we serve the right code at the right time. Thanks, Loadable!

What about errors and delays?

If the imported component will load fast, there is no need to flash a “loading” component. Thankfully, Loadable has the ability to delay the loading component from showing. This is helpful to prevent it from displaying too early where it feels silly and instead show it after a notable period of time has passed where we would expect to have seen it loaded.

To do that, our sample Loadable component will look like this;

const LoadableHello = Loadable({ 	loader: () => import('./Hello'), 	loading: Loader, 	delay: 300 })

Here, we are passing the Hello component as a value to loading, which is imported via loader. By default, delay is set to 200ms, but we’ve set ours a little later to 300ms.

Now let’s add a condition to the Loader component that tells it to display the loader only after the 300ms delay we set has passed:

const Loader = (props) => { 	if (props.pastDelay) { 		return <h2>Loading...</h2> 	} else { 		return null 	} }

So the Loader component will only show if the Hello component does not show after 300ms.

react-loader also gives us an error prop which we can use to return errors that are encountered. And, because it is a prop, we can let it spit out whatever we want.

const Loader = (props) => { 	if (props.error) { 		return <div>Oh no, something went wrong!</div>; 	} else if (props.delay) { 		return <h2>Loading...</h2> 	} else { 		return null; 	} }

Note that we’re actually combining the delay and error handling together! If there’s an error off the bat, we’ll display some messaging. If there’s no error, but 300ms have passed, then we’ll show a loader. Otherwise, load up the Hello component, please!

That’s a wrap

Isn’t it great that we have more freedom and flexibility in how we load and display code these days? Code splitting — either by component or by route — is the sort of thing React was designed to do. React allows us to write modular components that contain isolated code and we can serve them whenever and wherever we want and allow them to interact with the DOM and other components. Very cool!

Hopefully this gives you a good feel for code splitting as a concept. As you get your hands dirty and start using it, it’s worth checking out more in-depth posts to get a deeper understanding of the concept.

The post Using React Loadable for Code Splitting by Components and Routes appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]