Tag: Front

Rendering External API Data in WordPress Blocks on the Front End

There’ve been some new tutorials popping here on CSS-Tricks for working with WordPress blocks. One of them is an introduction to WordPress block development and it’s a good place to learn what blocks are and to register them in WordPress for use in pages and posts.

While the block basics are nicely covered in that post, I want to take it another step forward. You see, in that article, we learned the difference between rendering blocks in the back-end WordPress Block Editor and rendering them on the front-end theme. The example was a simple Pullquote Block that rendered different content and styles on each end.

Let’s go further and look at using dynamic content in a WordPress block. More specifically, let’s fetch data from an external API and render it on the front end when a particular block is dropped into the Block Editor.

We’re going to build a block that outputs data that shows soccer (er, football) rankings pulled from Api-Football.

An ordered set of football team rankings showing team logos, names, and game results.
This is what we’re working for together.

There’s more than one way to integrate an API with a WordPress block! Since the article on block basics has already walked through the process of making a block from scratch, we’re going to simplify things by using the @wordpress/create-block package to bootstrap our work and structure our project.

Initializing our block plugin

First things first: let’s spin up a new project from the command line:

npx @wordpress/create-block football-rankings

I normally would kick a project like this off by making the files from scratch, but kudos to the WordPress Core team for this handy utility!

Once the project folder has been created by the command, we technically have a fully-functional WordPress block registered as a plugin. So, let’s go ahead and drop the project folder into the wp-content/plugins directory where you have WordPress installed (probably best to be working in a local environment), then log into the WordPress admin and activate it from the Plugins screen.

Now that our block is initialized, installed, and activated, go ahead and open up the project folder from at /wp-content/plugins/football-rankings. You’re going to want to cd there from the command line as well to make sure we can continue development.

These are the only files we need to concentrate on at the moment:

  • edit.js
  • index.js
  • football-rankings.php

The other files in the project are important, of course, but are inessential at this point.

Reviewing the API source

We already know that we’re using Api-Football which comes to us courtesy of RapidAPI. Fortunately, RapidAPI has a dashboard that automatically generates the required scripts we need to fetch the API data for the 2021 Premier League Standings.

A dashboard interface with three columns showing code and data from an API source.
The RapidAPI dashboard

If you want to have a look on the JSON structure, you can generate visual representation with JSONCrack.

Fetching data from the edit.js file

I am going to wrap the RapidAPI code inside a React useEffect() hook with an empty dependency array so that it runs only once when the page is loaded. This way, we prevent WordPress from calling the API each time the Block Editor re-renders. You can check that using wp.data.subscribe() if you care to.

Here’s the code where I am importing useEffect(), then wrapping it around the fetch() code that RapidAPI provided:

/** * The edit function describes the structure of your block in the context of the * editor. This represents what the editor will render when the block is used. * * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit * * @return {WPElement} Element to render. */  import { useEffect } from "@wordpress/element";  export default function Edit(props) {   const { attributes, setAttributes } = props;    useEffect(() => {     const options = {       method: "GET",       headers: {         "X-RapidAPI-Key": "Your Rapid API key",         "X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",       },     };      fetch("https://api-football-v1.p.rapidapi.com/v3/standings?season=2021&league=39", options)       .then( ( response ) => response.json() )       .then( ( response ) => {         let newData = { ...response };         setAttributes( { data: newData } );         console.log( "Attributes", attributes );       })       .catch((err) => console.error(err)); }, []);    return (     <p { ...useBlockProps() }>       { __( "Standings loaded on the front end", "external-api-gutenberg" ) }     </p>   ); }

Notice that I have left the return function pretty much intact, but have included a note that confirms the football standings are rendered on the front end. Again, we’re only going to focus on the front end in this article — we could render the data in the Block Editor as well, but we’ll leave that for another article to keep things focused.

Storing API data in WordPress

Now that we are fetching data, we need to store it somewhere in WordPress. This is where the attributes.data object comes in handy. We are defining the data.type as an object since the data is fetched and formatted as JSON. Make sure you don’t have any other type or else WordPress won’t save the data, nor does it throw any error for you to debug.

We define all this in our index.js file:

registerBlockType( metadata.name, {   edit: Edit,   attributes: {     data: {       type: "object",     },   },   save, } );

OK, so WordPress now knows that the RapidAPI data we’re fetching is an object. If we open a new post draft in the WordPress Block Editor and save the post, the data is now stored in the database. In fact, if we can see it in the wp_posts.post_content field if we open the site’s database in phpMyAdmin, Sequel Pro, Adminer, or whatever tool you use.

Showing a large string of JSON output in a database table.
API output stored in the WordPress database

Outputting JSON data in the front end

There are multiple ways to output the data on the front end. The way I’m going to show you takes the attributes that are stored in the database and passes them as a parameter through the render_callback function in our football-rankings.php file.

I like keeping a separation of concerns, so how I do this is to add two new files to the block plugin’s build folder: frontend.js and frontend.css (you can create a frontend.scss file in the src directory which compiled to CSS in the build directory). This way, the back-end and front-end codes are separate and the football-rankings.php file is a little easier to read.

/explanation Referring back to the introduction to WordPress block development, there are editor.css and style.css files for back-end and shared styles between the front and back end, respectively. By adding frontend.scss (which compiles to frontend.css, I can isolate styles that are only intended for the front end.

Before we worry about those new files, here’s how we call them in football-rankings.php:

/** * Registers the block using the metadata loaded from the `block.json` file. * Behind the scenes, it registers also all assets so they can be enqueued * through the block editor in the corresponding context. * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ function create_block_football_rankings_block_init() {   register_block_type( __DIR__ . '/build', array(     'render_callback' => 'render_frontend'   )); } add_action( 'init', 'create_block_football_rankings_block_init' );  function render_frontend($ attributes) {   if( !is_admin() ) {     wp_enqueue_script( 'football_rankings', plugin_dir_url( __FILE__ ) . '/build/frontend.js');     wp_enqueue_style( 'football_rankings', plugin_dir_url( __FILE__ ) . '/build/frontend.css' ); // HIGHLIGHT 15,16,17,18   }      ob_start(); ?>    <div class="football-rankings-frontend" id="league-standings">     <div class="data">       <pre>         <?php echo wp_json_encode( $ attributes ) ?>       </pre>     </div>     <div class="header">       <div class="position">Rank</div>       <div class="team-logo">Logo</div>       <div class="team-name">Team name</div>       <div class="stats">         <div class="games-played">GP</div>         <div class="games-won">GW</div>         <div class="games-drawn">GD</div>         <div class="games-lost">GL</div>         <div class="goals-for">GF</div>         <div class="goals-against">GA</div>         <div class="points">Pts</div>       </div>       <div class="form-history">Last 5 games</div>     </div>     <div class="league-table"></div>   </div>    <?php return ob_get_clean(); }

Since I am using the render_callback() method for the attributes, I am going to handle the enqueue manually just like the Block Editor Handbook suggests. That’s contained in the !is_admin() condition, and is enqueueing the two files so that we avoid enqueuing them while using the editor screen.

Now that we have two new files we’re calling, we’ve gotta make sure we are telling npm to compile them. So, do that in package.json, in the scripts section:

"scripts": {   "build": "wp-scripts build src/index.js src/frontend.js",   "format": "wp-scripts format",   "lint:css": "wp-scripts lint-style",   "lint:js": "wp-scripts lint-js",   "packages-update": "wp-scripts packages-update",   "plugin-zip": "wp-scripts plugin-zip",   "start": "wp-scripts start src/index.js src/frontend.js" },

Another way to include the files is to define them in the block metadata contained in our block.json file, as noted in the introduction to block development:

"viewScript": [ "file:./frontend.js", "example-shared-view-script" ], "style": [ "file:./frontend.css", "example-shared-style" ],

The only reason I’m going with the package.json method is because I am already making use of the render_callback() method.

Rendering the JSON data

In the rendering part, I am concentrating only on a single block. Generally speaking, you would want to target multiple blocks on the front end. In that case, you need to make use of document.querySelectorAll() with the block’s specific ID.

I’m basically going to wait for the window to load and grab data for a few key objects from JSON and apply them to some markup that renders them on the front end. I am also going to convert the attributes data to a JSON object so that it is easier to read through the JavaScript and set the details from JSON to HTML for things like the football league logo, team logos, and stats.

The “Last 5 games” column shows the result of a team’s last five matches. I have to manually alter the data for it since the API data is in a string format. Converting it to an array can help make use of it in HTML as a separate element for each of a team’s last five matches.

import "./frontend.scss";  // Wait for the window to load window.addEventListener( "load", () => {   // The code output   const dataEl = document.querySelector( ".data pre" ).innerHTML;   // The parent rankings element   const tableEl = document.querySelector( ".league-table" );   // The table headers   const tableHeaderEl = document.querySelector( "#league-standings .header" );   // Parse JSON for the code output   const dataJSON = JSON.parse( dataEl );   // Print a little note in the console   console.log( "Data from the front end", dataJSON );      // All the teams    let teams = dataJSON.data.response[ 0 ].league.standings[ 0 ];   // The league logo   let leagueLogoURL = dataJSON.data.response[ 0 ].league.logo;   // Apply the league logo as a background image inline style   tableHeaderEl.style.backgroundImage = `url( $ { leagueLogoURL } )`;      // Loop through the teams   teams.forEach( ( team, index ) => {     // Make a div for each team     const teamDiv = document.createElement( "div" );     // Set up the columns for match results     const { played, win, draw, lose, goals } = team.all;      // Add a class to the parent rankings element     teamDiv.classList.add( "team" );     // Insert the following markup and data in the parent element     teamDiv.innerHTML = `       <div class="position">         $ { index + 1 }       </div>       <div class="team-logo">         <img src="$ { team.team.logo }" />       </div>       <div class="team-name">$ { team.team.name }</div>       <div class="stats">         <div class="games-played">$ { played }</div>         <div class="games-won">$ { win }</div>         <div class="games-drawn">$ { draw }</div>         <div class="games-lost">$ { lose }</div>         <div class="goals-for">$ { goals.for }</div>         <div class="goals-against">$ { goals.against }</div>         <div class="points">$ { team.points }</div>       </div>       <div class="form-history"></div>     `;          // Stringify the last five match results for a team     const form = team.form.split( "" );          // Loop through the match results     form.forEach( ( result ) => {       // Make a div for each result       const resultEl = document.createElement( "div" );       // Add a class to the div       resultEl.classList.add( "result" );       // Evaluate the results       resultEl.innerText = result;       // If the result a win       if ( result === "W" ) {         resultEl.classList.add( "win" );       // If the result is a draw       } else if ( result === "D" ) {         resultEl.classList.add( "draw" );       // If the result is a loss       } else {         resultEl.classList.add( "lost" );       }       // Append the results to the column       teamDiv.querySelector( ".form-history" ).append( resultEl );     });      tableEl.append( teamDiv );   }); });

As far as styling goes, you’re free to do whatever you want! If you want something to work with, I have a full set of styles you can use as a starting point.

I styled things in SCSS since the @wordpress/create-block package supports it out of the box. Run npm run start in the command line to watch the SCSS files and compile them to CSS on save. Alternately, you can use npm run build on each save to compile the SCSS and build the rest of the plugin bundle.

body {   background: linear-gradient(to right, #8f94fb, #4e54c8); }  .data pre {   display: none; }  .header {   display: grid;   gap: 1em;   padding: 10px;   grid-template-columns: 1fr 1fr 3fr 4fr 3fr;   align-items: center;   color: white;   font-size: 16px;   font-weight: 600;   background-repeat: no-repeat;   background-size: contain;   background-position: right; }  .frontend#league-standings {   width: 900px;   margin: 60px 0;   max-width: unset;   font-size: 16px;    .header {     .stats {       display: flex;       gap: 15px;        &amp; &gt; div {         width: 30px;       }     }   } }  .league-table {   background: white;   box-shadow:     rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,     rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;   padding: 1em;    .position {     width: 20px;   }    .team {     display: grid;     gap: 1em;     padding: 10px 0;     grid-template-columns: 1fr 1fr 3fr 4fr 3fr;     align-items: center;   }    .team:not(:last-child) {     border-bottom: 1px solid lightgray;   }    .team-logo img {     width: 30px;   }    .stats {     display: flex;     gap: 15px;   }    .stats &gt; div {     width: 30px;     text-align: center;   }    .form-history {     display: flex;     gap: 5px;   }    .form-history &gt; div {     width: 25px;     height: 25px;     text-align: center;     border-radius: 3px;     font-size: 15px;   }    .form-history .win {     background: #347d39;     color: white;   }    .form-history .draw {     background: gray;     color: white;   }    .form-history .lost {     background: lightcoral;     color: white;   } }

Here’s the demo!

Check that out — we just made a block plugin that fetches data and renders it on the front end of a WordPress site.

We found an API, fetch()-ed data from it, saved it to the WordPress database, parsed it, and applied it to some HTML markup to display on the front end. Not bad for a single tutorial, right?

Again, we can do the same sort of thing so that the rankings render in the Block Editor in addition to the theme’s front end. But hopefully keeping this focused on the front end shows you how fetching data works in a WordPress block, and how the data can be structured and rendered for display.

Rendering External API Data in WordPress Blocks on the Front End originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, , , , ,

Building a Cool Front End Thing Generator

Whether you are just starting out on the front end, or you’ve been doing it for a long time, building a tool that can generate some cool front-end magic can help you learn something new, develop your skills and maybe even get you a little notoriety.

You might have run across some of these popular online generators:

I’ve had fun building a few of these myself over the years. Basically, any time you run across some cool front-end thing, there might be an opportunity to make an interactive generator for that thing.

In this case, we are going to make an Animated Background Gradient Generator.

Scaffolding the project in Next

A nice thing about these projects is that they’re all yours. Choose whatever stack you want and get going. I’m a big fan of Next.js, so for this project, I’m going to start as a basic Create Next App project.

npx create-next-app animated-gradient-background-generator 

This generates all the files we need to get started. We can edit pages/index.js to be the shell for our project.

import Head from "next/head" import Image from "next/image" export default function Home() {   return (     <>       <Head>         <title>Animated CSS Gradient Background Generator</title>         <meta name="description" content="A tool for creating animated background gradients in pure CSS." />         <link rel="icon" href="/favicon.ico" />       </Head>       <main>         <h1>           Animated CSS Gradient Background Generator         </h1>       </main>     </>   ) }

Animated gradients?

At the time I’m writing this article, if you do a search for animated CSS gradient background, the first result is this Pen by Manuel Pinto.

Let’s take a look at the CSS:

body {   background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);   background-size: 400% 400%;   animation: gradient 15s ease infinite; }  @keyframes gradient {   0% {     background-position: 0% 50%;   }   50% {     background-position: 100% 50%;   }   100% {     background-position: 0% 50%;   } } 

This is a great example that we can use as the foundation for the generated animation.

A React component to describe an animated gradient

We can break out a few possible configurable options for the generator:

  • An array of gradient colors
  • The angle of the gradient
  • The speed of the animation

To put in context, we want to provide these settings as data throughout our little app using a higher-order component, context/SettingsContext.js, along with some defaults.

import React, { useState, createContext } from "react"  const SettingsContext = createContext({ colorSelection: [] })  const SettingsProvider = ({ children }) => {   const [colorSelection, setColorSelection] = useState([     "deepskyblue",     "darkviolet",     "blue",   ])   const [angle, setAngle] = useState(300)   const [speed, setSpeed] = useState(5)      return (     <SettingsContext.Provider       value={{         colorSelection,         setColorSelection,         angle,         setAngle,         speed,         setSpeed,       }}     >       {children}     </SettingsContext.Provider>   ) }  export { SettingsContext, SettingsProvider }

For our generator’s components, we want to create:

  • a control components to adjust these settings,
  • a visual display component for generated animated gradient, and
  • a component for the CSS code output.

Let’s start with a Controls component that contains the various inputs we used to adjust the settings.

import Colors from "./Colors"  const Controls = (props) => (   <>     <Colors />   </> )  export default Controls

We can add our SettingsProvider and Controls components to pages/index.js:

import Head from "next/head" import Image from "next/image" import { SettingsProvider } from "../context/SettingsContext" import Controls from "../components/Controls" import Output from "../components/Output"  export default function Home() {   return (     <>       <Head>         ...       </Head>        <SettingsProvider>         <main style={{ textAlign: "center", padding: "64px" }}>           <h1>Animated CSS Gradient Background Generator</h1>           <Controls />           <Output />         </main>       </SettingsProvider>     </>   ) }

Our SettingsProvider begins with the three colors from our CodePen example as defaults. We can verify that we are getting the color settings via our SettingsContext in a new Colors component.

import React, { useContext } from "react" import { SettingsContext } from "../context/SettingsContext"  const Colors = () => {   const { colorSelection } = useContext(SettingsContext)   return (     <>       {colorSelection.map((color) => (         <div>{color}</div>       ))}     </>   ) }  export default Colors

Let’s use the Colors component to display individual color swatches with a small button to delete via our SettingsContext.

import React, { useContext } from "react" import { SettingsContext } from "../context/SettingsContext"  const Colors = () => {   const { colorSelection, setColorSelection } = useContext(SettingsContext)    const onDelete = (deleteColor) => {     setColorSelection(colorSelection.filter((color) => color !== deleteColor))   }    return (     <div>       {colorSelection.map((color) => (         <div           key={color}           style={{             background: color,             display: "inline-block",             padding: "32px",             margin: "16px",             position: "relative",             borderRadius: "4px",           }}         >           <button             onClick={() => onDelete(color)}             style={{               background: "crimson",               color: "white",               display: "inline-block",               borderRadius: "50%",               position: "absolute",               top: "-8px",               right: "-8px",               border: "none",               fontSize: "18px",               lineHeight: 1,               width: "24px",               height: "24px",               cursor: "pointer",               boxShadow: "0 0 1px #000",             }}           >             ×           </button>         </div>       ))}     </div>   ) }  export default Colors

You may notice that we have been using inline styles for CSS at this point. Who cares! We’re having fun here, so we can do whatever floats our boats.

Handling colors

Next, we create an AddColor component with a button that opens a color picker used to add more colors to the gradient.

For the color picker, we will install react-color and use the ChromePicker option.

npm install react-color

Once again, we will utilize SettingsContext to update the gradient color selection.

import React, { useState, useContext } from "react" import { ChromePicker } from "react-color" import { SettingsContext } from "../context/SettingsContext"  const AddColor = () => {   const [color, setColor] = useState("white")   const { colorSelection, setColorSelection } = useContext(SettingsContext)    return (     <>       <div style={{ display: "inline-block", paddingBottom: "32px" }}>         <ChromePicker           header="Pick Colors"           color={color}           onChange={(newColor) => {             setColor(newColor.hex)           }}         />       </div>       <div>         <button           onClick={() => {             setColorSelection([...colorSelection, color])           }}           style={{             background: "royalblue",             color: "white",             padding: "12px 16px",             borderRadius: "8px",             border: "none",             fontSize: "16px",             cursor: "pointer",             lineHeight: 1,           }}         >           + Add Color         </button>       </div>     </>   ) }  export default AddColor

Handling angle and speed

Now that our color controls are finished, let’s add some components with range inputs for setting the angle and animation speed.

Here’s the code for AngleRange, with SpeedRange being very similar.

import React, { useContext } from "react" import { SettingsContext } from "../context/SettingsContext"  const AngleRange = () => {   const { angle, setAngle } = useContext(SettingsContext)    return (     <div style={{ padding: "32px 0", fontSize: "18px" }}>       <label         style={{           display: "inline-block",           fontWeight: "bold",           width: "100px",           textAlign: "right",         }}         htmlFor="angle"       >         Angle       </label>       <input         type="range"         id="angle"         name="angle"         min="-180"         max="180"         value={angle}         onChange={(e) => {           setAngle(e.target.value)         }}         style={{           margin: "0 16px",           width: "180px",           position: "relative",           top: "2px",         }}       />       <span         style={{           fontSize: "14px",           padding: "0 8px",           position: "relative",           top: "-2px",           width: "120px",           display: "inline-block",         }}       >         {angle} degrees       </span>     </div>   ) }  export default AngleRange

Now for the fun part: rendering the animated background. Let’s apply this to the entire background of the page with an AnimatedBackground wrapper component.

import React, { useContext } from "react" import { SettingsContext } from "../context/SettingsContext" const AnimatedBackground = ({ children }) => {   const { colorSelection, speed, angle } = useContext(SettingsContext) const background =   "linear-gradient(" + angle + "deg, " + colorSelection.toString() + ")" const backgroundSize =   colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%" const animation =   "gradient-animation " +   colorSelection.length * Math.abs(speed - 11) +   "s ease infinite" return (   <div style={{ background, "background-size": backgroundSize, animation, color: "white" }}>     {children}   </div>   ) } export default AnimatedBackground

We’re calling the CSS animation for the gradient gradient-animation. We need to add that to styles/globals.css to trigger the animation:

@keyframes gradient-animation {   0% {     background-position: 0% 50%;   }   50% {     background-position: 100% 50%;   }   100% {     background-position: 0% 50%;   } } 

Making it useful to users

Next, let’s add some code output so people can copy and paste the generated CSS and use in their own projects.

import React, { useContext, useState } from "react" import { SettingsContext } from "../context/SettingsContext" const Output = () => {   const [copied, setCopied] = useState(false) const { colorSelection, speed, angle } = useContext(SettingsContext) const background =   "linear-gradient(" + angle + "deg," + colorSelection.toString() + ")" const backgroundSize =   colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%" const animation =   "gradient-animation " +   colorSelection.length * Math.abs(speed - 11) +   "s ease infinite" const code = `.gradient-background {   background: $  {background};   background-size: $  {backgroundSize};   animation: $  {animation}; } @keyframes gradient-animation {   0% {     background-position: 0% 50%;   }   50% {     background-position: 100% 50%;   }   100% {     background-position: 0% 50%;   } }` return (     <div       style={{ position: "relative", maxWidth: "640px", margin: "64px auto" }}     >       <pre         style={{           background: "#fff",           color: "#222",           padding: "32px",           width: "100%",           borderRadius: "4px",           textAlign: "left",           whiteSpace: "pre",           boxShadow: "0 2px 8px rgba(0,0,0,.33)",           overflowX: "scroll",         }}       >         <code>{code}</code>         <button           style={{             position: "absolute",             top: "8px",             right: "8px",             background: "royalblue",             color: "white",             padding: "8px 12px",             borderRadius: "8px",             border: "none",             fontSize: "16px",             cursor: "pointer",             lineHeight: 1,           }}           onClick={() => {             setCopied(true)             navigator.clipboard.writeText(code)           }}         >           {copied ? "copied" : "copy"}         </button>       </pre>     </div>   ) } export default Output

Making it fun

It is sometimes fun (and useful) to add a button that sets random values on a generator like this. That gives people a way to quickly experiment and see what kinds of results they can get out of the tool. It is also an opportunity to look up cool stuff like how to generate random hex colors.

import React, { useContext } from "react" import { SettingsContext } from "../context/SettingsContext"  const Random = () => {   const { setColorSelection, setAngle, setSpeed } = useContext(SettingsContext)    const goRandom = () => {     const numColors = 3 + Math.round(Math.random() * 3)     const colors = [...Array(numColors)].map(() => {       return "#" + Math.floor(Math.random() * 16777215).toString(16)     })     setColorSelection(colors)     setAngle(Math.floor(Math.random() * 361))     setSpeed(Math.floor(Math.random() * 10) + 1)   }    return (     <div style={{ padding: "48px 0 16px" }}>       <button         onClick={goRandom}         style={{           fontSize: "24px",           fontWeight: 200,           background: "rgba(255,255,255,.9)",           color: "blue",           padding: "24px 48px",           borderRadius: "8px",           cursor: "pointer",           boxShadow: "0 0 4px #000",           border: "none",         }}       >         RANDOM       </button>     </div>   ) }  export default Random

Wrapping up

There will be a few final things you’ll want to do to wrap up your project for initial release:

  • Update package.json with your project information.
  • Add some links to your personal site, the project’s repository and give credit where its due.
  • Update the README.md file that was generated with default content by Create Next App.

That’s it! We’re ready to release our new cool front end thing generator and reap the rewards of fame and fortune that await us!

You can see the code for this project on GitHub and the demo is hosted on Netlify.

The post Building a Cool Front End Thing Generator appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.


, , , ,

Front of the Front / Back of the Front

People really latched onto Brad’s framing. And for good reason. Front-end development has gotten so wide scoping that there are specialists inside of it. Two years ago, I cut it down the middle and now Brad is putting a point on that here, saying he has actual clients who have shifted their hiring strategy away from full-stack and toward these exact distinctions. Nice.

Brad shoots for a simple distinction:

A succinct way I’ve framed the split is that a front-of-the-front-end developer determines the look and feel of a button, while a back-of-the-front-end developer determines what happens when that button is clicked.

Part of me loves the clarity there. And part of me like But! But! Wait! I’m a front-of-the-front kinda guy, but I totally deal with what happens on click. I’m a state updating machine over here. I’ll fire off that GraphQL mutation myself, thankyouverymuch. I friggin own that onClick.

And yet, I still don’t feel back-of-the-front at all. I can’t set up that GraphQL API or troubleshoot it. I don’t know what the security implications of the network request is. I don’t know if the query I wrote will be performant or not, nor where to look at a graph to find out. I think I’d draw the line in a slightly different place than Brad, but he knows that. He’s flexible here:

The line between front-of-the-front-end and back-of-the-front-end can be fuzzy and varies greatly from developer to developer. It’s totally possible that one developer might be able to perform many tasks across the front-end spectrum. But it’s also worth pointing out that’s not super common.

That’s why the term full-stack isn’t my favorite. I bet an awful lot of developers have skill sets on both sides of the “great divide”, which I think makes it feel like you’re full-stack when it’s more likely you’re cross-stack. Full-stack makes me feel like you’re deeply knowledgeable about literally everything across not only the front-end spectrum but back-end too. Brad says that’s not common and I’ll up that and say it’s downright rare.

My main regret about trying to cut front-end development in half is that it’s too clean of a metaphor for a messy thing.

I live in Bend, Oregon where outdoor hobbies are like the main thing. You don’t really go up and ask people if they are a summer sports person or a winter sports person because they are almost always both. But one person might be into snowshoeing, downhill skiing, and day hiking, where the next person might be into paddle boarding, nordic skiing, and mountain biking. So I had this idea of Bend Name Tags where it lists all the outdoor hobbies and you write your name and then circle all the ones that you’re into.

It should almost be like that with front-end development. You write your name and then list out all the things you’re into. Me? I like HTML, CSS, JavaScript, Build Processes, Design, React, WordPress, with a dash of Accessibility, Performance, and Copywriting. What does that make me? Me.

Direct Link to ArticlePermalink

The post Front of the Front / Back of the Front appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



Getting the WordPress Block Editor to Look Like the Front End Design

I’m a WordPress user and, if you’re anything like me, you always have two tabs open when you edit a post: one with the new fancy pants block editor, aka Gutenberg, and another with a preview of the post so you know it won’t look wonky on the front end.

It’s no surprise that a WordPress theme’s styles only affect the front end of your website. The back end posy editor generally looks nothing like the front end result. We’re used to it. But what if I said it’s totally possible for the WordPress editor nearly mirror the front end appearance?

All it takes is a custom stylesheet.

Mind. Blown. Right? Well, maybe it’s not that mind blowing, but it may save you some time if nothing else. 🙂

WordPress gives us a hint of what’s possible here. Fire up the default Twenty Twenty theme that’s packaged with WordPress, fire up the editor, and it sports some light styling.

This whole thing consists of two pretty basic changes:

  1. A few lines of PHP in your theme’s functions.php file that tell the editor you wish to load a custom stylesheet for editor styles
  2. Said custom stylesheet

Right then, enough pre-waffle! Let’s get on with making the WordPress editor look like the front end, shall we?

Step 1: Crack open the functions.php file

OK I was lying, just a little more waffling. If you’re using a WordPress theme that you don’t develop yourself, it’s probably best that you setup a child theme before making any changes to your main theme. </pre-waffle>

Fire up your favorite text editor and open up the theme’s functions.php file that’s usually located in the root of the theme folder. Let’s drop in the following lines at the end of the file:

// Gutenberg custom stylesheet add_theme_support('editor-styles'); add_editor_style( 'style-editor.css' ); // make sure path reflects where the file is located

What this little snippet of code does is tell WordPress to add support for a custom stylesheet to be used with Gutenberg, then points to where that stylesheet (that we’re calling editor-style.css) is located. WordPress has solid documentation for the add_theme_support function if you want to dig into it a little more.

Step 2: CSS tricks (see what I did there?!)

Now we’re getting right into our wheelhouse: writing CSS!

We’ve added editor-styles support to our theme, so the next thing to do is to add the CSS goodness to the stylesheet we defined in functions.php so our styles correctly load up in Gutenberg.

There are thousands of WordPress themes out there, so I couldn’t possibly write a stylesheet that makes the editor exactly like each one. Instead, I will show you an example based off of the theme I use on my website. This should give you an idea of how to build the stylesheet for your site. I’ll also include a template at the end, which should get you started.

OK let’s create a new file called style-editor.css and place it in the root directory of the theme (or again, the child theme if you’re customizing a third-party theme).

Writing CSS for the block editor isn’t quite as simple as using standard CSS elements. For example, if we were to use the following in our editor stylesheet it wouldn’t apply the text size to <h2> elements in the post.

h2 {   font-size: 1.75em; }

Instead of elements, our stylesheet needs to target Block Editor blocks. This way, we know the formatting should be as accurate as possible. That means <h2> elements needs to be scoped to the .rich-text.block-editor-rich-text__editable class to style things up.

Showing the block editor with a light yellow background, a heading that reads Holly Dolly, and a heading 2 with DevTools open to the left in dark mode and a block-editor-rich-text-__editor class highlighted in red.
It just takes a little peek at DevTools to find a class we can latch onto.
h2.rich-text.block-editor-rich-text__editable {   font-size: 1.75em; }

I just so happened to make a baseline CSS file that styles common block editor elements following this pattern. Feel free to snag it over at GitHub and swap out the styles so they complement your theme.

I could go on building the stylesheet here, but I think the template gives you an idea of what you need to populate within your own stylesheet. A good starting point is to go through the stylesheet for your front-end and copy the elements from there, but you will likely need to change some of the element classes so that they apply to the Block Editor window.

If in doubt, play around with elements in your browser’s DevTools to work out what classes apply to which elements. The template linked above should capture most of the elements though.

The results

First of all, let’s take a look at what the WordPress editor looks like without a custom stylesheet:

Showing the WordPress block editor without any custom styling, which is a plain white screen with black text including a heading one paragraph, a blockquote and a black rounded button.
The block editor sports a clean, stark UI in its default appearance. It’s pulling in Noto Serif from Google Fonts but everything else is pretty bare bones.

Let’s compare that to the front end of my test site:

Showing a webpage with the same heading, paragraph, blockquote and button, but with styles that include a red-to-orange gradient that goes left-to-right as a background behind the white heading, a typewriter-like font, the same gradient to style the blockquote borders and text, and to style the button.

Things are pretty different, right? Here we still have a simple design, but I’m using gradients all over, to the max! There’s also a custom font, button styling, and a blockquote. Even the containers aren’t exactly square edges.

Love it or hate it, I think you will agree this is a big departure from the default Gutenberg editor UI. See why I have to have a separate tab open to preview my posts?

Now let’s load up our custom styles and check things out:

The same look as the custom styles on the front end but now displayed in the WordPress block editor.

Well would you look at that! The editor UI now looks pretty much exactly the same as the front end of my website. The content width, fonts, colors and various elements are all the same as the front end. I even have the fancy background against the post title!

Ipso facto — no more previews in another tab. Cool, huh?

Making the WordPress editor look like your front end is a nice convenience. When I’m editing a post, flipping between tabs to see what the posts looks like on the front end ruins my mojo, so I prefer not to do it.

These couple of quick steps should be able to do the same for you, too!

The post Getting the WordPress Block Editor to Look Like the Front End Design appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , , , ,

Getting Started with Front End Testing

Amy Kapernick covers four types of testing that front-end devs could and should be doing:

  1. Linting (There’s ESLint for JavaScript and Stylelint or Prettier for CSS.)
  2. Accessibility Testing (Amy recommends pa11y, and we’ve covered Axe.)
  3. Visual Regression Testing (Amy recommends Backstop, and we’ve covered Percy.)
  4. End to End Testing (There’s Cypress and stuff like jest-puppeteer.)

Amy published something similar over on 24 ways, listing out 12 different testing tools.

As long as we’re being comprehensive, we might consider performance testing to be part of all this, ala SpeedCurve or Calibre to mention some web services.

I’ve liked what Harry Roberts has said lately about performance budgets. They don’t need to be fancy; they just need to prevent you from bad screwups.

[…] most organisations aren’t ready for challenges, they’re in need of safety nets. Performance budgets should not be things to work toward, they should be things that stop us slipping past a certain point. They shouldn’t be aspirational, they should be preventative.

Direct Link to ArticlePermalink

The post Getting Started with Front End Testing appeared first on CSS-Tricks.


, , ,