Developer News

Getting to Know the useReducer React Hook

Css Tricks - Wed, 06/26/2019 - 3:59am

useReducer is one of a handful of React hooks that shipped in React 16.7.0. It accepts a reducer function with the application initial state, returns the current application state, then dispatches a function.

Here is an example of how it is used;

const [state, dispatch] = useReducer(reducer, initialState);

What’s the good for? Well, think about any situation where having the first loaded state of the application might be nice. Let’s say the starting point on an interactive map. Maybe it’s an app that lets the user build a custom car with custom options from a default model. Here’s a pretty neat demo of a calculator app that puts useRedcuer to use in order to reset the calculator to a default state of zero when clearing it out.

See the Pen
Basic React Hook Calculator
by Gianpierangelo De Palma (@dpgian)
on CodePen.

We’re going to dig into a couple more examples in this post, but let’s first look at the hook itself to get a better idea of what it is and what exactly it does when it’s used.

The almighty reducer

It’s tough to talk about useState without also mentioning JavaScript’s reduce method. We linked it up at the very top, but Sarah’s post is an excellent overview of reducers and helps set the state for where we’re going here.

The first and most important thing to understand about a reducer is that it will always only return one value. The job of a reducer is to reduce. That one value can be a number, a string, an array or an object, but it will always only be one. Reducers are really great for a lot of things, but they're especially useful for applying a bit of logic to a group of values and ending up with another single result.

So, if we have an array of numbers, reduce will distill it down to a single number that adds up for as many times as there are values. Say we have this simple array:

const numbers = [1, 2, 3]

...and we have a function that logs each time our reducer makes a calculation into the console. This will help us see how reduce distills the array into a single number.

const reducer = function (tally, number) { console.log(`Tally: ${tally}, Next number: ${number}, New Total: ${tally + number}`) return tally + number }

Now let’s run a reducer on it. As we saw earlier, reduce takes dispatches a function that runs against a default state. Let’s plug our reducer function and an initial value of zero in there.

const total = numbers.reduce(reducer, 0)

Here’s what gets logged to the console:

"Tally: 0, Next number: 1, New Total: 1" "Tally: 1, Next number: 2, New Total: 3" "Tally: 3, Next number: 3, New Total: 6"

See how reduce takes an initial value and builds on it as each number in the array is added to it until we get a final value? In this case, that final value is 6.

I also really like this (modified) example from Dave Ceddia that shows how reduce can be used on an array of letters to spell a word:

var letters = ['r', 'e', 'd', 'u', 'c', 'e']; // `reduce` takes 2 arguments: // - a function to do the reducing (you might say, a "reducer") // - an initial value for accumulatedResult var word = letters.reduce( function(accumulatedResult, arrayItem) { return accumulatedResult + arrayItem; }, ''); // <-- notice this empty string argument: it's the initial value console.log(word) // => "reduce" useReducer works with states and actions

OK, that was a lot of refresher to get what we’re really talking about: userReducer. It’s important to get all this, though, because you may have noticed where we’re going now after having seen the way reduce fires a function against an initial value. It’s the same sort of concept, but returns two elements as an array, the current state and a dispatch function.

In other words:

const [state, dispatch] = useReducer(reducer, initialArg, init);

What’s up with that third init argument? It’s an optional value that will lazily create the initial state. That means we can calculate the initial state/value with an init function outside of the reducer instead of providing an explicit value. That’s handy if the initial value could be different, say based on a last saved state instead of a consistent value.

To get it working, we need to do a few things:

  • Define an initial state.
  • Provide a function that contains actions that update the state.
  • Trigger userReducer to dispatch an updated state that’s calculated relative to the initial state.

The classic example of this a counter application. In fact, that’s what React’s docs use to drive the concept home. Here’s that put into practice:

See the Pen
React useReducer 1
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

It’s a good example because it demonstrates how an initial state (a zero value) is used to calculate a new value each time an action is fired by clicking either the increase or decrease button. We could even throw in a “Reset" button in there to clear the total back to the initial state of zero.

Example: A Car Customizer

See the Pen
React useReducer - car example
by Geoff Graham (@geoffgraham)
on CodePen.

In this example, we are making the assumption that the user has selected a car to purchase. However, we want the app to allow the user to add extra options to the car. Each option has a price that adds to the base total.

First, we need to create the initial state which will consist of the car, an empty array to keep track of features, and an additional price that starts at $26,395 and a list of items in the store, so the user can pick what they want.

const initialState = { additionalPrice: 0, car: { price: 26395, name: "2019 Ford Mustang", image: "https://cdn.motor1.com/images/mgl/0AN2V/s1/2019-ford-mustang-bullitt.jpg", features: [] }, store: [ { id: 1, name: "V-6 engine", price: 1500 }, { id: 2, name: "Racing detail package", price: 1500 }, { id: 3, name: "Premium sound system", price: 500 }, { id: 4, name: "Rear spoiler", price: 250 } ] };

Our reducer function will handle two things: the addition and removal of new items.

const reducer = (state, action) => { switch (action.type) { case "REMOVE_ITEM": return { ...state, additionalPrice: state.additionalPrice - action.item.price, car: { ...state.car, features: state.car.features.filter((x) => x.id !== action.item.id)}, store: [...state.store, action.item] }; case "BUY_ITEM": return { ...state, additionalPrice: state.additionalPrice + action.item.price, car: { ...state.car, features: [...state.car.features, action.item] }, store: state.store.filter((x) => x.id !== action.item.id) } default: return state; } }

When the user selects the item she wants, we update the features for the car, increase the additionalPrice and also remove the item from the store. We ensure that the other parts of the state remain as they are.
We do something similar when a user removes an item from the features list - reduce the additional price, return the item to the store.
Here is how the App component looks like.

const App = () => { const inputRef = useRef(); const [state, dispatch] = useReducer(reducer, initialState); const removeFeature = (item) => { dispatch({ type: 'REMOVE_ITEM', item }); } const buyItem = (item) => { dispatch({ type: 'BUY_ITEM', item }) } return ( <div> <div className="box"> <figure className="image is-128x128"> <img src={state.car.image} /> </figure> <h2>{state.car.name}</h2> <p>Amount: ${state.car.price}</p> <div className="content"> <h6>Extra items you bought:</h6> {state.car.features.length ? ( <ol type="1"> {state.car.features.map((item) => ( <li key={item.id}> <button onClick={() => removeFeature(item)} className="button">X </button> {item.name} </li> ))} </ol> ) : <p>You can purchase items from the store.</p> } </div> </div> <div className="box"> <div className="content"> <h4>Store:</h4> {state.store.length ? ( <ol type="1"> {state.store.map((item) => ( <li key={item.id}>\ <button onClick={() => buyItem(item)} className="button">Buy </button> {item.name} </li> ))} </ol> ) : <p>No features</p> } </div> <div className="content"> <h4> Total Amount: ${state.car.price + state.additionalPrice} </h4> </div> </div> </div> ); }

The actions that get dispatched contains the details of the selected item. We make use of the action type to determine how the reducer function will handle the updating of the state. You can see that the rendered view changes based on what you do - buying an item from the store removes the item from the store and adds it to the list of features. Also, the total amount gets updated. No doubt, there are some improvements that can be done to the application, this is only for learning purpose.

What about useState? Can’t we use that instead?

An astute reader may have been asking this all along. I mean, setState is generally the same thing, right? Return a stateful value and a function to re-render a component with that new value.

const [state, setState] = useState(initialState);

We could have even used the useState() hook in the counter example provided by the React docs. However, useReducer is preferred in cases where state has to go through complicated transitions. Kent C. Dodds wrote up a explanation of the differences between the two and (while he often reaches for setState) he provides a good use case for using userReducer instead:

If your one element of your state relies on the value of another element of your state, then it's almost always best to use useReducer

For example, imagine you have a tic-tac-toe game you're writing. You have one element of state called squares which is just an array of all the squares and their value[.]

My rule of thumb is to reach for useReducer to handle complex states, particularly where the initial state is based on the state of other elements.

Oh wait, we already have Redux for this!

Those of you who have worked with Redux already know everything we’ve covered here and that’s because it was designed to use the Context API to pass stored states between components — without having to pass props through other components to get there.

So, does useReducer replace Redux? Nope. I mean, you can basically make your own Redux by using it with the useContext hook, but that’s doesn’t mean Redux is useless; Redux still has plenty of other features and benefits worth considering.

Where have you used userReducer? Have you found clear-cut cases where it’s better than setState? Maybe you can experiment with the things we covered here to build something. Here are a few ideas:

  • A calendar that focus at today’s date but allows a user to select other dates. Maybe even add a “Today" button that returns the user to today’s date.
  • You can try improving on the car example - have a list of cars that users can purchase. You might have to define this in the initial state, then the user can add extra features they want with a charge. These features can be predefined, or defined by the user.

Getting to Know the useReducer React Hook

Css Tricks - Wed, 06/26/2019 - 3:59am

useReducer is one of a handful of React hooks that shipped in React 16.7.0. It accepts a reducer function with the application initial state, returns the current application state, then dispatches a function.

Here is an example of how it is used;

const [state, dispatch] = useReducer(reducer, initialState);

What’s the good for? Well, think about any situation where having the first loaded state of the application might be nice. Let’s say the starting point on an interactive map. Maybe it’s an app that lets the user build a custom car with custom options from a default model. Here’s a pretty neat demo of a calculator app that puts useRedcuer to use in order to reset the calculator to a default state of zero when clearing it out.

See the Pen
Basic React Hook Calculator
by Gianpierangelo De Palma (@dpgian)
on CodePen.

We’re going to dig into a couple more examples in this post, but let’s first look at the hook itself to get a better idea of what it is and what exactly it does when it’s used.

The almighty reducer

It’s tough to talk about useState without also mentioning JavaScript’s reduce method. We linked it up at the very top, but Sarah’s post is an excellent overview of reducers and helps set the state for where we’re going here.

The first and most important thing to understand about a reducer is that it will always only return one value. The job of a reducer is to reduce. That one value can be a number, a string, an array or an object, but it will always only be one. Reducers are really great for a lot of things, but they're especially useful for applying a bit of logic to a group of values and ending up with another single result.

So, if we have an array of numbers, reduce will distill it down to a single number that adds up for as many times as there are values. Say we have this simple array:

const numbers = [1, 2, 3]

...and we have a function that logs each time our reducer makes a calculation into the console. This will help us see how reduce distills the array into a single number.

const reducer = function (tally, number) { console.log(`Tally: ${tally}, Next number: ${number}, New Total: ${tally + number}`) return tally + number }

Now let’s run a reducer on it. As we saw earlier, reduce takes dispatches a function that runs against a default state. Let’s plug our reducer function and an initial value of zero in there.

const total = numbers.reduce(reducer, 0)

Here’s what gets logged to the console:

"Tally: 0, Next number: 1, New Total: 1" "Tally: 1, Next number: 2, New Total: 3" "Tally: 3, Next number: 3, New Total: 6"

See how reduce takes an initial value and builds on it as each number in the array is added to it until we get a final value? In this case, that final value is 6.

I also really like this (modified) example from Dave Ceddia that shows how reduce can be used on an array of letters to spell a word:

var letters = ['r', 'e', 'd', 'u', 'c', 'e']; // `reduce` takes 2 arguments: // - a function to do the reducing (you might say, a "reducer") // - an initial value for accumulatedResult var word = letters.reduce( function(accumulatedResult, arrayItem) { return accumulatedResult + arrayItem; }, ''); // <-- notice this empty string argument: it's the initial value console.log(word) // => "reduce" useReducer works with states and actions

OK, that was a lot of refresher to get what we’re really talking about: userReducer. It’s important to get all this, though, because you may have noticed where we’re going now after having seen the way reduce fires a function against an initial value. It’s the same sort of concept, but returns two elements as an array, the current state and a dispatch function.

In other words:

const [state, dispatch] = useReducer(reducer, initialArg, init);

What’s up with that third init argument? It’s an optional value that will lazily create the initial state. That means we can calculate the initial state/value with an init function outside of the reducer instead of providing an explicit value. That’s handy if the initial value could be different, say based on a last saved state instead of a consistent value.

To get it working, we need to do a few things:

  • Define an initial state.
  • Provide a function that contains actions that update the state.
  • Trigger userReducer to dispatch an updated state that’s calculated relative to the initial state.

The classic example of this a counter application. In fact, that’s what React’s docs use to drive the concept home. Here’s that put into practice:

See the Pen
React useReducer 1
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

It’s a good example because it demonstrates how an initial state (a zero value) is used to calculate a new value each time an action is fired by clicking either the increase or decrease button. We could even throw in a “Reset" button in there to clear the total back to the initial state of zero.

Example: A Car Customizer

See the Pen
React useReducer - car example
by Geoff Graham (@geoffgraham)
on CodePen.

In this example, we are making the assumption that the user has selected a car to purchase. However, we want the app to allow the user to add extra options to the car. Each option has a price that adds to the base total.

First, we need to create the initial state which will consist of the car, an empty array to keep track of features, and an additional price that starts at $26,395 and a list of items in the store, so the user can pick what they want.

const initialState = { additionalPrice: 0, car: { price: 26395, name: "2019 Ford Mustang", image: "https://cdn.motor1.com/images/mgl/0AN2V/s1/2019-ford-mustang-bullitt.jpg", features: [] }, store: [ { id: 1, name: "V-6 engine", price: 1500 }, { id: 2, name: "Racing detail package", price: 1500 }, { id: 3, name: "Premium sound system", price: 500 }, { id: 4, name: "Rear spoiler", price: 250 } ] };

Our reducer function will handle two things: the addition and removal of new items.

const reducer = (state, action) => { switch (action.type) { case "REMOVE_ITEM": return { ...state, additionalPrice: state.additionalPrice - action.item.price, car: { ...state.car, features: state.car.features.filter((x) => x.id !== action.item.id)}, store: [...state.store, action.item] }; case "BUY_ITEM": return { ...state, additionalPrice: state.additionalPrice + action.item.price, car: { ...state.car, features: [...state.car.features, action.item] }, store: state.store.filter((x) => x.id !== action.item.id) } default: return state; } }

When the user selects the item she wants, we update the features for the car, increase the additionalPrice and also remove the item from the store. We ensure that the other parts of the state remain as they are.
We do something similar when a user removes an item from the features list - reduce the additional price, return the item to the store.
Here is how the App component looks like.

const App = () => { const inputRef = useRef(); const [state, dispatch] = useReducer(reducer, initialState); const removeFeature = (item) => { dispatch({ type: 'REMOVE_ITEM', item }); } const buyItem = (item) => { dispatch({ type: 'BUY_ITEM', item }) } return ( <div> <div className="box"> <figure className="image is-128x128"> <img src={state.car.image} /> </figure> <h2>{state.car.name}</h2> <p>Amount: ${state.car.price}</p> <div className="content"> <h6>Extra items you bought:</h6> {state.car.features.length ? ( <ol type="1"> {state.car.features.map((item) => ( <li key={item.id}> <button onClick={() => removeFeature(item)} className="button">X </button> {item.name} </li> ))} </ol> ) : <p>You can purchase items from the store.</p> } </div> </div> <div className="box"> <div className="content"> <h4>Store:</h4> {state.store.length ? ( <ol type="1"> {state.store.map((item) => ( <li key={item.id}>\ <button onClick={() => buyItem(item)} className="button">Buy </button> {item.name} </li> ))} </ol> ) : <p>No features</p> } </div> <div className="content"> <h4> Total Amount: ${state.car.price + state.additionalPrice} </h4> </div> </div> </div> ); }

The actions that get dispatched contains the details of the selected item. We make use of the action type to determine how the reducer function will handle the updating of the state. You can see that the rendered view changes based on what you do - buying an item from the store removes the item from the store and adds it to the list of features. Also, the total amount gets updated. No doubt, there are some improvements that can be done to the application, this is only for learning purpose.

What about useState? Can’t we use that instead?

An astute reader may have been asking this all along. I mean, setState is generally the same thing, right? Return a stateful value and a function to re-render a component with that new value.

const [state, setState] = useState(initialState);

We could have even used the useState() hook in the counter example provided by the React docs. However, useReducer is preferred in cases where state has to go through complicated transitions. Kent C. Dodds wrote up a explanation of the differences between the two and (while he often reaches for setState) he provides a good use case for using userReducer instead:

If your one element of your state relies on the value of another element of your state, then it's almost always best to use useReducer

For example, imagine you have a tic-tac-toe game you're writing. You have one element of state called squares which is just an array of all the squares and their value[.]

My rule of thumb is to reach for useReducer to handle complex states, particularly where the initial state is based on the state of other elements.

Oh wait, we already have Redux for this!

Those of you who have worked with Redux already know everything we’ve covered here and that’s because it was designed to use the Context API to pass stored states between components — without having to pass props through other components to get there.

So, does useReducer replace Redux? Nope. I mean, you can basically make your own Redux by using it with the useContext hook, but that’s doesn’t mean Redux is useless; Redux still has plenty of other features and benefits worth considering.

Where have you used userReducer? Have you found clear-cut cases where it’s better than setState? Maybe you can experiment with the things we covered here to build something. Here are a few ideas:

  • A calendar that focus at today’s date but allows a user to select other dates. Maybe even add a “Today" button that returns the user to today’s date.
  • You can try improving on the car example - have a list of cars that users can purchase. You might have to define this in the initial state, then the user can add extra features they want with a charge. These features can be predefined, or defined by the user.

The post Getting to Know the useReducer React Hook appeared first on CSS-Tricks.

Spam Detection APIs

Css Tricks - Tue, 06/25/2019 - 4:06am

I was trying to research the landscape of these the other day — And by research, I mean light Googling and asking on Twitter. Weirdly, very little comes to mind when thinking about spam detection APIs. I mean some kind of URL endpoint, paid or not, where you can hit it with a block of text and whatever metadata it wants and it'll tell you if it's spam or not. Seems like something an absolute buttload of the internet could use and something companies of any size could monetize or offer free to show off their smart computer machines.

Akismet is the big kid on the block.

You might think of Akismet as a WordPress thing, and it is. It's an Automattic product and is perhaps primarily used as a WordPress plugin. I run that here on CSS-Tricks and it's blocked 1,989,326 so far.

It also has a generic API. There are libraries for Dart, JavaScript, PHP, Python, Ruby, Go, etc, as well as plugins for other CMSs. So if you use a different CMS or have your custom app, you can still use Akismet for spam detection.

After you get an API key, you can POST to a URL endpoint with all the data it needs and it'll respond true if it's spam or false if it's not.

To get better results over time, you can also submit content telling it if it's spam or ham (ham is the opposite of spam... good content).

Plino

Several folks mentioned Plino to me.

There is a lot to like here, like the fact that it's free and returns a JSON response like you might be used to in development. There is the fancy buzzword "Machine Learning" being used here, too. It makes me think that with lots of people using this, it'll get smarter and smarter as it goes. But there is no way to submit ham/spam, so I'm not sure that's really the case.

There is other stuff that makes me nervous. It's clearly on Heroku which is kinda expensive at scale, and so with no pricing model it seems like it could go away anytime. Sorta feels like a fun-but-abandoned side project. Last commit was two years ago, as I write.

OOPSpam

OOPSpam looks super similar to Plino, but has a pricing model, which is nice. They publish their latency, which is over two seconds. I haven't compared that to the others so I have no idea if they are all that slow. Two seconds seems like a lot for an API call to me, but maybe it's not that big of a deal since it's an async submit?

CleanTalk

CleanTalk has a clear pricing structure and appears to have plenty of customers, which is a plus to me. The website looks a little janky though, which makes me worry a little.

(Sorry if that's a little rude, but it's just mental math to me. Good design is one of the least expensive investments a company can make to increase trust, so companies that overlook it make me wonder.)

It looks like they have a variety of anti-spam solutions though, which is interesting. For example, you can ask an API to see if an IP, email, or domain is on a blacklist, which is a pretty raw way of blocking bad stuff, but useful for stuff like protecting against spam registrations (rather than just checking blocks of text). They also have a firewall solution, which is interesting for folks trying to block spam before it even touches their servers.

Email options...

There are a couple out there that seem rather specific to testing emails. As in, testing your own emails before you send them to make sure they aren't considered spam by email services. Here are a couple I cam across while looking around:

The post Spam Detection APIs appeared first on CSS-Tricks.

Spam Detection APIs

Css Tricks - Tue, 06/25/2019 - 4:06am

I was trying to research the landscape of these the other day — And by research, I mean light Googling and asking on Twitter. Weirdly, very little comes to mind when thinking about spam detection APIs. I mean some kind of URL endpoint, paid or not, where you can hit it with a block of text and whatever metadata it wants and it'll tell you if it's spam or not. Seems like something an absolute buttload of the internet could use and something companies of any size could monetize or offer free to show off their smart computer machines.

Akismet is the big kid on the block.

You might think of Akismet as a WordPress thing, and it is. It's an Automattic product and is perhaps primarily used as a WordPress plugin. I run that here on CSS-Tricks and it's blocked 1,989,326 so far.

It also has a generic API. There are libraries for Dart, JavaScript, PHP, Python, Ruby, Go, etc, as well as plugins for other CMSs. So if you use a different CMS or have your custom app, you can still use Akismet for spam detection.

After you get an API key, you can POST to a URL endpoint with all the data it needs and it'll respond true if it's spam or false if it's not.

To get better results over time, you can also submit content telling it if it's spam or ham (ham is the opposite of spam... good content).

Plino

Several folks mentioned Plino to me.

There is a lot to like here, like the fact that it's free and returns a JSON response like you might be used to in development. There is the fancy buzzword "Machine Learning" being used here, too. It makes me think that with lots of people using this, it'll get smarter and smarter as it goes. But there is no way to submit ham/spam, so I'm not sure that's really the case.

There is other stuff that makes me nervous. It's clearly on Heroku which is kinda expensive at scale, and so with no pricing model it seems like it could go away anytime. Sorta feels like a fun-but-abandoned side project. Last commit was two years ago, as I write.

OOPSpam

OOPSpam looks super similar to Plino, but has a pricing model, which is nice. They publish their latency, which is over two seconds. I haven't compared that to the others so I have no idea if they are all that slow. Two seconds seems like a lot for an API call to me, but maybe it's not that big of a deal since it's an async submit?

CleanTalk

CleanTalk has a clear pricing structure and appears to have plenty of customers, which is a plus to me. The website looks a little janky though, which makes me worry a little.

(Sorry if that's a little rude, but it's just mental math to me. Good design is one of the least expensive investments a company can make to increase trust, so companies that overlook it make me wonder.)

It looks like they have a variety of anti-spam solutions though, which is interesting. For example, you can ask an API to see if an IP, email, or domain is on a blacklist, which is a pretty raw way of blocking bad stuff, but useful for stuff like protecting against spam registrations (rather than just checking blocks of text). They also have a firewall solution, which is interesting for folks trying to block spam before it even touches their servers.

Email options...

There are a couple out there that seem rather specific to testing emails. As in, testing your own emails before you send them to make sure they aren't considered spam by email services. Here are a couple I cam across while looking around:

The post Spam Detection APIs appeared first on CSS-Tricks.

Why I don’t use web components

Css Tricks - Tue, 06/25/2019 - 4:06am

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.

Why I don’t use web components

Css Tricks - Tue, 06/25/2019 - 4:06am

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.

Render Snarky Comments in Comic Sans

Css Tricks - Mon, 06/24/2019 - 12:29pm

Hilarious idea by Zach Leatherman. To test if a comment is "snarky" or not, there is an npm package up to the task.

On this site, we generally just delete snarky comments, but I still run a WordPress plugin that allows me to "feature" or "bury" comments. It's old but it still works fine in the latest WordPress. We use the bury functionality for comments that aren't rude, snarky, or spam, but also don't add much to the post. We try to downplay those so they aren't wasting people's time scrolling through the threads.

I dig the Comic Sans idea, so I'm gonna give it a shot. &#x1f609;

Direct Link to ArticlePermalink

The post Render Snarky Comments in Comic Sans appeared first on CSS-Tricks.

Building a Conference Schedule with CSS Grid

Css Tricks - Mon, 06/24/2019 - 4:21am

It’s hard to beat the feeling of finding a perfect use for a new technology. You can read every handy primer under the sun and ooh-and-ahh at flashy demos, but the first time you use it on your own project… that’s when things really click.

I gained a new appreciation for CSS Grid when building a flexible layout for a conference schedule. The needs of the project aligned perfectly with grid’s strengths: a two-dimensional (vertical and horizontal) layout with complex placement of child elements. In the process of building a proof of concept, I found a few techniques that made the code highly readable and outright fun to work with.

The resulting demo included some interesting uses of CSS Grid features and forced me to grapple with some details of grid you don’t run into in every day.

Before we get started, it might be a good idea to keep another tab open with the CSS-Tricks guide to CSS Grid to reference the concepts we cover throughout the post.

Defining our layout requirements

I set out to create the following layout thanks to WordCamp, the hundreds of WordPress-focused conferences that happen around the world each year. These varied events range in size and format, yet all use the same schedule layout tool.

The final layout we’ll build.

I helped schedule a couple WordCamps and styled a WordCamp website, so I knew the shortcomings of the existing HTML table layout. If your schedule didn’t fit in a uniform grid, well…¯\_(?)_/¯

Setting out to find a better way, I started by listing the layout requirements:

  • Sessions of variable length (limited to set time increments)
    Imagine back-to-back one-hour talks in three rooms alongside a two-hour workshop in another.
  • Sessions spanning one or more "Tracks"
    Tracks are usually associated with a specific room in the venue. In the case of my local WordCamp in Seattle, the venue can literally remove a wall to combine two rooms!
  • Schedule can include empty space
    A last-minute cancellation or extra-short session creates gaps in a schedule.
  • Design is easy to customize with CSS
    WordCamp websites allow theming only via CSS.
  • Layout can be automatically generated from CMS content
    Since we’re building a layout from structured session data on thousands of websites, we can’t rely on any HTML or CSS that’s too clever or bespoke.
Getting started: Solid HTML

Before I write any CSS, I always start with rock-solid HTML.

The top-level <div> will have a class of .schedule and serve as the grid parent. Each unique start time gets its own heading followed by all sessions starting at that time. The markup for each session isn’t very important, but make sure that seeing the layout isn’t required to understand when and where a session happens. (You’ll see why in a moment.)

<h2>Conference Schedule</h2> <div class="schedule"> <h3 class="time-slot">8:00am</h3> <div class="session session-1 track-1"> <h4 class="session-title"><a href="#">Session Title</a></h4> <span class="session-time">8:00am - 9:00am</span> <span class="session-track">Track 1</span> <span class="session-presenter">Presenter Name</span> </div> <!-- Sessions 2, 3, 4 --> <h3 class="time-slot">9:00am</h3> <div class="session session-5 track-1"> <h4 class="session-title"><a href="#">Session Title</a></h4> <span class="session-time">9:00am - 10:00am</span> <span class="session-track">Track 1</span> <span class="session-presenter">Presenter Name</span> </div> <!-- Sessions 6, 7, 8 --> <!-- etc... --> </div> <!-- end .schedule --> Mobile layout and grid fallback complete!

Adding in a bit of up-to-you CSS to make things pretty, our mobile layout and fallback for browsers that don’t support CSS Grid is already complete!

Here’s how mine looks with the colors I used:

People on phones, zooming in their browsers, or even using Internet Explorer will have no problem finding their favorite sessions at this conference! Adding the grid layout

Now for the actual CSS Grid part!

My ah-ha moment when building this came from reading Robin’s article here on CSS-Tricks, "Making a Bar Chart with CSS Grid." TL;DR: One grid row represents 1% of the chart's height, so a bar spans the same number of rows as the percentage it represents.

.chart { display: grid; grid-template-rows: repeat(100, 1fr); /* 1 row = 1%! */ } .fifty-percent-bar { grid-row: 51 / 101; /* 101 - 51 = 50 => 50% */ }

That helped me realize that grid is perfect for any layout tied to some regular incremental unit. In the case of a schedule, that unit is time! For this demo, we’ll use increments of 30 minutes, but do whatever makes sense for you. (Just watch out for the Chrome bug that limits Grid layouts to 1000 rows.)

The first version I tried used similar syntax to the bar chart in Robin’s and some basic math to place the sessions. We’re using eight rows because there are eight 30-minute increments between 8 a.m. and 12 p.m. Remember that implicit grid line numbers start at one (not zero), so the grid rows are numbered one through nine.

A rudimentary version of a single column schedule with numbered grid lines. (View Demo: Numbered Gridlines vs. Named Gridlines) .schedule { display: grid; grid-template-rows: repeat(8, 1fr); } .session-1 { grid-row: 1 / 3; /* 8am - 9am, 3 - 1 = 2 30-minute increment */ } .session-2 { grid-row: 3 / 6; /* 9am - 10:30am, 6-3 = 3 30-minute increments */ }

The problem with this technique is that placing items on a grid with a lot of rows is very abstract and confusing. (This issue added a ton of complexity to Robin’s bar chart demo, too.)

This is where named grid lines come to the rescue! Instead of relying on grid line numbers, we can give each line a predictable name based on the corresponding time of day.

By using named grid lines for the schedule, it becomes much easier to place a session. (View Demo: Numbered Gridlines vs. Named Gridlines) .schedule { display: grid; grid-template-rows: [time-0800] 1fr [time-0830] 1fr [time-0900] 1fr [time-0930] 1fr; /* etc... Note: Use 24-hour time for line names */ } .session-1 { grid-row: time-0800 / time-0900; } .session-2 { grid-row: time-0900 / time-1030; }

That is gloriously easy to understand. There is no complicated math to figure out how many rows there are before and after a session starts or ends. Even better, we can generate grid line names and session layout styles with information stored in WordPress. Throw a start and end time at the grid, and you’re good to go!

Since the schedule has multiple tracks, we’ll need a column for each one. The tracks work in a similar way to the times, using named track lines for each grid column line. There’s also an extra first column for the start time headings.

.schedule { /* continued */ grid-template-columns: [times] 4em [track-1-start] 1fr [track-1-end track-2-start] 1fr [track-2-end track-3-start] 1fr [track-3-end track-4-start] 1fr [track-4-end]; }

Here though, we take named grid lines one step further. Each line gets two names: one for the track it starts and one for the track it ends. This isn’t strictly necessary, but it makes the code much clearer, especially when a session spans more than one column.

With the time- and track-based grid lines defined, we can now place any session we want just from knowing it’s time and track!

.session-8 { grid-row: time-1030 / time-1100; grid-column: track-2-start / track-3-end; /* spanning two tracks! */ }

Putting that all together, we get some lengthy but extremely readable code that is a real joy to work with.

@media screen and (min-width: 700px) { .schedule { display: grid; grid-gap: 1em; grid-template-rows: [tracks] auto /* Foreshadowing! */ [time-0800] 1fr [time-0830] 1fr [time-0900] 1fr [time-0930] 1fr [time-1000] 1fr [time-1030] 1fr [time-1100] 1fr [time-1130] 1fr [time-1200] 1fr; grid-template-columns: [times] 4em [track-1-start] 1fr [track-1-end track-2-start] 1fr [track-2-end track-3-start] 1fr [track-3-end track-4-start] 1fr [track-4-end]; } .time-slot { grid-column: times; } } <div class="session session-1 track-1" style="grid-column: track-1; grid-row: time-0800 / time-0900;"> <!-- details --> </div> <div class="session session-2 track-2" style="grid-column: track-2; grid-row: time-0800 / time-0900"> <!-- details --> </div> <!-- etc... -->

The final code uses inline styles for session placement which feels right to me. If you don’t like this and are working with more modern browsers, you could pass the line names to CSS via CSS variables.

Quick note: using fr units versus the auto value for row heights

One detail worth noting is the use of the fr unit for defining row heights.

When using 1fr to determine row heights, all rows have the same height. That height is determined by the content of the tallest row in the schedule. (I had to read the W3C spec for fr to figure this out!) That produces a beautiful schedule where height is proportional to time, but can also lead to a very tall layout.

Using 1fr produces equal-height rows determined by the tallest row in the grid. (View Demo: Grid row heights 1fr vs auto)

For example, if your schedule grid has 15-minute increments from 7 a.m. to 6 p.m., that’s a total of 48 grid rows. In that case, you probably want to use auto for your row height because the schedule is much more compact with each grid row's height determined by its content.

Using auto makes each row the height of its content. (View Demo: Grid row heights 1fr vs auto) A word about accessibility

There are real concerns about the accessibility of certain CSS Grid techniques. Specifically, the ability to change the order of information visually in ways that don’t match the source order causes problems for people using keyboard navigation.

This layout uses that ability to arbitrarily place items on a grid, so some caution is warranted. However, because the heading and source order align with the visualization of start times, this seems like a safe use to me.

If you’re inspired to do something similar, carefully consider accessibility. It makes sense to order information by time in this case, but I can imagine a legitimate case for TAB order to go down columns rather than across rows. (Modifying this demo to do that shouldn’t be too hard!)

Whatever you do, always consider accessibility.

Adding sticky track names

Finally, it’s time to add in the track names that look like table headers at the top of each column. Since a session’s track is already visible, I chose to hide the "headers" from assistive technology with aria-hidden="true".

The track names go in the first grid row, conveniently named "tracks." As long as you don’t have any weird overflow issues, position: sticky keeps those in view while you scroll.

<span class="track-slot" aria-hidden="true" style="grid-column: track-1;">Track 1</span> <span class="track-slot" aria-hidden="true" style="grid-column: track-2;">Track 2</span> <span class="track-slot" aria-hidden="true" style="grid-column: track-3;">Track 3</span> <span class="track-slot" aria-hidden="true" style="grid-column: track-4;">Track 4</span> .track-slot { display: none; /* only visible with Grid layout */ } @supports( display:grid ) { @media screen and (min-width:700px) { .track-slot { grid-row: tracks; display: block; position: sticky; top: 0; z-index: 1000; background-color: rgba(255,255,255,.9); } } }

It’s a slick little finishing touch to the final demo. ✨

The result

Here’s how things look with everything we’ve covered put together!

See the Pen
Conference Schedule with CSS Grid
by Mark Root-Wiley (@mrwweb)
on CodePen.

We’re just getting started

This schedule is definitely the most satisfying use of CSS Grid I’ve ever made. I love how "data-driven" and semantic the line naming is, and the accessibility and CMS requirements fit in perfectly without any inconvenience.

The only question left for me is what other types of "data-driven" grids are out there to build? I’ve seen some great calendar layouts and here’s a Monopoly board layout. What about a football field, a timeline, restaurant tables, or theater seats? What else?

The post Building a Conference Schedule with CSS Grid appeared first on CSS-Tricks.

Reduced Motion Picture Technique, Take Two

Css Tricks - Fri, 06/21/2019 - 5:11am

Did you see that neat technique for using the <picture> element with <source media=""> to serve an animated image (or not) based on a prefers-reduced-motion media query?

After we shared that in our newsletter, we got an interesting reply from Michael Gale:

What about folks who love their animated GIFs, but just didn’t want the UI to be zooming all over the place? Are they now forced to make a choice between content and UI?

I thought that was a pretty interesting question.

Also, whenever I see <img src="gif.gif"> these days, my brain is triggered into WELL WHAT ABOUT MP4?! territory, as I've been properly convinced that videos are better-in-all-ways on the web than GIFs. Turns out, some browsers support videos right within the <img> element and, believe it or not, you can write fallbacks for that, with — drumroll, please — for the <picture> element as well!

Let's take a crack at combining all this stuff.

Adding an MP4 source

The easy one is adding an additional <source> with the video. That means we'll need three source media files:

  1. A fallback non-animated graphic when prefers-reduced-motion is reduce.
  2. An animated GIF as the default.
  3. An MP4 video to replace the GIF, if the fallback is supported.

For example:

<picture> <source srcset="static.png" media="(prefers-reduced-motion: reduce)"></source> <source srcset="animated.mp4" type="video/mp4"> <img srcset="animated.gif" alt="animated image" /> </picture>

Under default conditions in Chrome, only the GIF is downloaded and shown:

Under default conditions in Safari, only the MP4 is downloaded and shown:

If you've activated prefers-reduced-motion: reduce in either Chrome or Safari (on my Mac, I go to System Preferences → Accessibility → Display → Reduce Motion), both browsers only download the static PNG file.

I tested Firefox and it doesn't seem to work, instead continuing to download the GIF version. Firefox seems to support prefers-reduced-motion, but perhaps it's just not supported on <source> elements yet? I'm not sure what's up there.

Wouldn't it be kinda cool to provide a single animated source and have a tool generate the others from it? I bet you could wire that up with something like Cloudinary.

Adding a toggle to show the animated version

Like Michael Gale mentioned, it seems a pity that you're entirely locked out from seeing the animated version just because you've flipped on a reduced motion toggle.

It should be easy enough to have a <button> that would use JavaScript to yank out the media query and force the browser to show the animated version.

I'm fairly sure there is no practical way to do this declaratively in HTML. We also can't put this button within the <picture> tag. Even though <picture> isn't a replaced element, the browser still gets confused and doesn't like it. Instead, it doesn't render it at all. No big deal, we can use a wrapper.

<div class="picture-wrap"> <picture> <!-- sources --> </picture> <button class="animate-button">Animate</button> </div>

We can position the button on top of the image somewhere. This is just an arbitrary choice — you could put it wherever you want, or even have the entire image be tappable as long as you think you could explain that to users. Remember to only show the button when the same media query matches:

.picture-wrap .animate-button { display: none; } @media (prefers-reduced-motion: reduce) { .picture-wrap .animate-button { display: block; } }

When the button is clicked (or tapped), we need to remove the media query to start the animation by downloading an animated source.

let button = document.querySelector(".animate-button"); button.addEventListener("click", () => { const parent = button.closest(".picture-wrap"); const picture = parent.querySelector("picture"); picture.querySelector("source[media]").remove(); });

Here's that in action:

See the Pen
Prefers Reduction Motion Technique PLUS!
by Chris Coyier (@chriscoyier)
on CodePen.

Maybe this is a good component?

We could automatically include the button, the button styling, and the button functionality with a web component. Hey, why not?

See the Pen
Prefers Reduction Motion Technique as Web Component
by Chris Coyier (@chriscoyier)
on CodePen.

The post Reduced Motion Picture Technique, Take Two appeared first on CSS-Tricks.

Weekly Platform News: Mozilla’s AV1 Encoder, Samsung One UI CSS, DOM Matches Method

Css Tricks - Fri, 06/21/2019 - 5:10am

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

In this week's weekly roundup, Vimeo and Mozilla partner up on a video encoding format, how to bind instructions to to form fields using aria labels, the DOM has a matching function, and Samsung is working on its own CSS library.

Vimeo partners with Mozilla to use their rav1e encoder

Vittorio Giovara: AV1 is a royalty-free video codec designed by the Alliance for Open Media and the the most anticipated successor of H.264. Vimeo is contributing to the development of Mozilla’s AV1 encoder.

In order for AV1 to succeed, there is a need of an encoder like x264, a free and open source encoder, written by the community, for the community, and available to everyone: rav1e. Vimeo believes in what Mozilla is doing.

Use aria-describedby to bind instructions to form fields

Raghavendra Satish Peri: If you provide additional instructions for a form field, use the aria-describedby attribute to bind the instruction to the field. Otherwise, assistive technology users who use the Tab key might miss this information.

<label for="dob">Date of Birth</label> <input type="text" aria-describedby="dob1" id="dob" /> <span id="dob1">Use DD/MM/YY</span> Samsung Internet announces One UI CSS

Diego González: Samsung is experimentally developing a CSS library based on its new One UI design language. The library is called One UI CSS and includes styles for common form controls such as buttons, menus, and sliders, as well as other assets (web fonts, SVG icons, polyfills).

Some of the controls present in One UI CSS. DOM elements have a matches method

Sam Thorogood: You can use the matches method to test if a DOM element has a specific CSS class, attribute or ID value. This method accepts a CSS selector and returns true if the element matches the given selector.

el.classList.has('foo') /* becomes */ el.matches('.foo'); el.hasAttribute('hello') /* becomes */ el.matches('[hello]'); el.id === 'bar' /* becomes */ el.matches('#bar');

The post Weekly Platform News: Mozilla’s AV1 Encoder, Samsung One UI CSS, DOM Matches Method appeared first on CSS-Tricks.

Hello Subgrid!

Css Tricks - Thu, 06/20/2019 - 10:48am

Rachel Andrew’s talk at CSSconf is wonderful because it digs into one of the most exciting changes that’s coming soon to a browser near you: subgrid! That’s a change to the CSS Grid spec that allows for much greater flexibility for our visual designs. Subgrid allows us to set one grid on an entire page and let child elements use that very same grid tracks.

The reason why I’m very excited is because this solves one of the most annoying visual layout issues that I’ve come across since becoming a web developer, and if that sounds bonkers and/or wonderful to you, then make sure to check out Rachel’s talk because she does a much better job of describing this than I possibly could:

Direct Link to ArticlePermalink

The post Hello Subgrid! appeared first on CSS-Tricks.

Managing WordPress Metadata in Gutenberg Using a Sidebar Plugin

Css Tricks - Thu, 06/20/2019 - 5:18am

WordPress released their anticipated over to the post editor, nicknamed Gutenberg, which is also referred to as the block editor. It transforms a WordPress post into a collection of blocks that you can add, edit, remove and re-order in the layout. Before the official release, Gutenberg was available as a plugin and, during that time, I was interested in learning how to create custom blocks for the editor. I was able to learn a lot about Gutenberg that I decided to put together a course that discusses almost everything you need to know to develop blocks for Gutenberg.

In this article, we will discuss metaboxes and metafields in WordPress. Specifically, we’ll cover how to replace the old PHP metaboxes in Gutenberg and extend Gutenberg’s sidebar to add a React component that will be used to manipulate the metadata using the global JavaScript Redux-like stores. Note that metadata in Gutenberg can also be manipulated using blocks. And both ways are discussed in my course, however, in this article I am going to focus on managing metadata in the sidebar since I believe this method will be used more often.

This article assumes some familiarity with ReactJS and Redux. Gutenberg relies heavily on these technologies to render UI and manage state. You can also check out the CSS-Tricks guide to learning Gutenberg for an intro to some of the concepts we’ll cover here.

The block editor interface Gutenberg is a React application

At its core, Gutenberg is a ReactJS application. Everything you see in the editor is rendered using a React component. The post title, the content area that contains the blocks, the toolbar at the top and the right sidebar are all React components. Data or application states in this React application are stored in centralized JavaScript objects, or "stores." These stores are managed by WordPress’ data module. This module shares a lot of core principles with Redux. So, concepts like stores, reducers, actions, action creators, etc., also exist in this module. I will sometimes refer to these stores as "Redux-like" stores.

These stores do not only store any data about the current post, like the post content (the blocks), the post title, and the selected categories, but it also stores global information about a WordPress website, like all the categories, tags, posts, attachments and so on. In addition to that, UI state information like,"is the sidebar opened or closed?" are also stored in these global stores. One of the jobs of the "data module" is to retrieve data from these stores and also change data in the stores. Since these stores are global and can be used by multiple React components changing data in any store will be reflected in any Gutenberg UI part (including blocks) that uses this piece of data.

Once a post is saved, the WordPress REST API will be used to update the post using the data stored in these global stores. So the post title, the content, categories etc., that are stored in these global stores will be sent as payload in the WP REST API endpoint that updates the post. And thus if we are able to manipulate data in these stores, once the user clicks save, the data that we manipulated will be stored in the database by the API without us having to do anything.

One of the things that is not managed by these global stores in Gutenberg is metadata. If you have some metafields that you used to manage using a metabox in the pre-Gutenberg "classic" editor, those will not be stored and manipulated using the global Redux-like stores by default. However, we can opt-in to manage metadata using JavaScript and the Redux-like stores. Although those old PHP metaboxes will still appear in Gutenberg, WordPress recommends porting these PHP metaboxes to another approach that uses the global stores and React components. And this will ensure a more unified and consistent experience. You can read more about problems that could occur by using PHP metaboxes in Gutenberg.

So before we start, let’s take a look at the Redux-like stores in Gutenberg and how to use them.

Retrieving and changing data in Gutenberg’s Redux-like stores

We now know that the Gutenberg page is managed using these Redux-like stores. We have some default "core" stores that are defined by WordPress. Additionally, we can also define our own stores if we have some data that we would like to share between multiple blocks or even between blocks and other UI elements in the Gutenberg page, like the sidebar. Creating your own stores is also discussed in my course and you can read about it in the official docs. However, in this article we will focus on how to use the existing stores. Using the existing stores lets us manipulate metadata; therefore we will not need to create any custom stores.

In order to access these stores, make sure you have the latest WordPress version with Gutenberg active and edit any post or page. Then, open your browser console an type the following statement:

wp.data.select('core/editor').getBlocks()

You should get something like this:

Let’s break this down. First, we access the wp.data module which (as we discussed) is responsible for managing the Redux-like stores. This module will be available inside the global wp variable if you have Gutenberg in your WordPress installation. Then, inside this module, we call a function called select. This function receives a store name as an argument and returns all the selectors for this store. A selector is a term used by the data module and it simply means a function that gets some data from the store. So, in our example, we accessed the core/editor store, and this will return a bunch of functions that can be used to get data from this store. One of these functions is getBlocks() which we called above. This function will return an array of objects where each object represents a block in your current post. So depending on how many blocks you have in your post, this array will change.

As we’ve seen, we accessed a store called core/editor. This store contains information about the current post that you are editing. We’ve also seen how to get the blocks in the current post but we can also get a lot of other stuff. We can get the title of the current post, the current post ID, the current post post type and pretty much everything else we might need.

But in the example above, we were only able to retrieve data. What if we want to change data? Let’s take a look at another selector in the ‘core/editor’ store. Let’s run this selector in our browser console:

wp.data.select('core/editor').getEditedPostAttribute('title')

This should return the title of the post currently being edited:

Great! Now what if we want to change the title using the data module? Instead of calling select(), we can call dispatch() which will also receive a store name and return some actions that you can dispatch. If you are familiar with Redux, terms like "actions" and "dispatch" will sound familiar to you. If this sounds new to you, all you need to know is that dispatching a certain action simply means changing some data in a store. In our case, we want to change the post title in the store, so we can call this function:

wp.data.dispatch('core/editor').editPost({title: 'My new title'})

Now take a look at the post title in the editor — it will be changed accordingly!

That’s how we can manipulate any piece of data in the Gutenberg interface. Wan retrieve the data using selectors and change that data using actions. Any change will be reflected in any part of the UI that uses this data.

There are, of course, other stores in Gutenberg that you can checkout on this page. So, let’s take a quick look at a couple of more stores before we move on.

The stores that you will use the most are the core/editor which we just looked at, and the core store. Unlike core/editor, the core store contains information, not only about the currently edited post, but also about the whole WordPress website in general. So, for instance, we can get all the authors on the website using:

wp.data.select('core').getAuthors()

We can also get some posts from the website like so:

wp.data.select('core').getEntityRecords('postType','post',{per_page: 5})

Make sure to run this twice if the first result was null. Some selectors like this one will send an API call first to get your post. That means the the returned value will initially be null until the API request is fulfilled:

Let’s look at one more store: edit-post. This store is responsible for the UI information in the actual editor. For example, we can have selectors that check if the sidebar is currently open:

wp.data.select('core/edit-post').isEditorSidebarOpened()

This will return true if the sidebar is opened. But try closing the sidebar, run this function again, and it should return false.

We can also open and close the sidebar by dispatching actions in this store. Having the sidebar open and running this action in the browser console, the sidebar should be closed:

wp.data.dispatch('core/edit-post').closeGeneralSidebar()

You will unlikely need to use this store, but it’s good to know that this is what Gutenberg does when you click on the sidebar icon to close it.

There are some more stores that you might need to take a look at. The core/notices store, for instance, could be useful. This can help you display error, warning and success messages in the Gutenberg page. You can also check all the other stores here.

Try to play around with these stores in your browser until you feel comfortable using them. After that, we can see how to use them in real code outside the browser.

Let’s setup a WordPress plugin to add a Gutenberg sidebar

Now that we know how to use the Redux-like stores in Gutenberg, the next step is to add a React sidebar component in the editor. This React component will be connected to the core/editor store and it will have some input that, when changed, will dispatch some action that will manipulate metadata — like the way we manipulated the post title earlier. But to do that, we need to create a WordPress plugin that holds our code.

You can follow along by cloning or downloading the repository for this example on GitHub.

Let’s create a new folder inside wp-content/plugins directory of the WordPress installation. I am going to call it gutenberg-sidebar. Inside this folder, let’s create the entry point for our plugin. The entry point is the PHP file that will be run when activating your plugin. It can be called index.php or plugin.php. We’re going to use plugin.php for this example and put some information about the plugin at the top as well as add some code that avoids direct access:

<?php /** * Plugin Name: gutenberg-sidebar * Plugin URI: https://alialaa.com/ * Description: Sidebar for the block editor. * Author: Ali Alaa * Author URI: https://alialaa.com/ */ if( ! defined( 'ABSPATH') ) { exit; }

You should find your plugin on the Plugins screen in the WordPress admin. Click on "Activate" in order for the code to run.

As you might imagine, we will write a lot of JavaScript and React from this point, forward. And in order to code React components easily we will need to use JSX. And JSX is not valid JavaScript that can run in your browser, it needs to be converted into plain JavaScript. We might also need to use ESNext features and import statements for importing and exporting modules.

And these features will not work on all browsers, so it’s better to transform our code into old ES5 JavaScript. Thankfully, there are a lot of tools that can help us achieve that. A famous one is webpack. webpack, however, is a big topic in itself and it won’t fit the scope of this article. Therefore, we are going to use another tool that WordPress provides which is @wordpress/scripts. By installing this package, we will get a recommended webpack configuration without having to do anything in webpack ourselves. Personally, I recommend that you learn webpack and try to do the configuration yourself. This will help you understand what’s going on and give you more control. You can find a lot of resources online and it’s also discussed in my course. But for now, let’s install the WordPress webpack configuration tool.

Change to your plugin folder in Terminal:

cd path/to/your/theme/folder

Next, we need to initialize npm in that folder in order to install @wordpress/scripts. This can be done by running this command:

npm init

This command will ask you some questions like the package name, version, license, etc. You can keep hitting Enter and leave the default values. You should have a package.json file in your folder and we can start installing npm packages. Let’s install @wordpress/scripts by running the following command:

npm install @wordpress/scripts --save-dev

This package will expose a CLI called wp-scripts which you can use in your npm scripts. There are different commands that you can run. We will focus on the build and start commands for now. The <code>build script will transform your files so that they are minified and ready for production. Your source code’s entry point is configured in src/index.js and the transformed output will be at build/index.js. Similarly, the start script will transform your code in src/index.js to build/index.js, however, this time, the code will not be minified to save time and memory — the command will also watch for changes in your files and re-build your files every time something is changed. The start command is suitable to be used for development while the build command is for production. To use these commands, we will replace the scripts key in the package.json file which will look something like this if you used the default options when we initialized npm.

Change this:

"scripts": { "test": "echo "Error: no test specified" && exit 1" },

...to this:

"scripts": { "start": "wp-scripts start", "build": "wp-scripts build" },

Now we can run npm start and npm run build to start development or build files, respectively.

Let’s create a new folder in the plugin’s root called src and add an index.js file in it. We can see it things are working by sprinkling in a little JavaScript. We’ll try an alert.

Now run npm start in Terminal. You should find the build folder created with the compiled index.js and also sourcemap files. In addition to that, you will notice that the build/index.js file is not minified and webpack will be watching for changes. Try changing the src/index.js file and save again. The build/index.js file will re-generated:

If you stop the watch (Ctrl + C ) in Terminal and run npm run build, the build/index.js file should now be minified.

Now that we have our JavaScript bundle, we need to enqueue this file in the Gutenberg editor. To do that we can use the hoo enqueue_block_editor_assets which will insure that the files are enqueued only in the Gutenberg page and not in other wp-admin pages where it isn’t needed.

We can enqueue our file like so in plugin.php:

// Note that it’s a best practice to prefix function names (e.g. myprefix) function myprefix_enqueue_assets() { wp_enqueue_script( 'myprefix-gutenberg-sidebar', plugins_url( 'build/index.js', __FILE__ ) ); } add_action( 'enqueue_block_editor_assets', 'myprefix_enqueue_assets' );

Visit the Gutenberg page. If all is well, you should get an alert, thanks to what we added to src/index.js earlier.

Fantastic! We’re ready to write some JavaScript code, so let’s get started!

Importing WordPress JavaScript packages

In order to add some content to the existing Gutenberg sidebar or create a new blank sidebar, we need to register a Gutenberg JavaScript plugin — and in order to do that, we need to use some functions and components from packages provided by WordPress: wp-plugins, wp-edit-post and wp-i18n. These packages will be available in the wp global variable in the browser as wp.plugins, wp.editPost and wp.i18n.

We can import the functions that we need into src/index.js. Specifically, those functions are: registerPlugin and PluginSidebar.

const { registerPlugin } = wp.plugins; const { PluginSidebar } = wp.editPost; const { __ } = wp.i18n;

It’s worth noting that we need to make sure that we have these files as dependencies when we enqueue our JavaScript file in order to make sure that our index.js file will be loaded after the wp-plugins, wp-edit-posts and wp-i18n packages. Let’s add those to plugin.php:

function myprefix_enqueue_assets() { wp_enqueue_script( 'myprefix-gutenberg-sidebar', plugins_url( 'build/index.js', __FILE__ ), array( 'wp-plugins', 'wp-edit-post', 'wp-i18n', 'wp-element' ) ); } add_action( 'enqueue_block_editor_assets', 'myprefix_enqueue_assets' );

Notice that I added wp-element in there as a dependency. I did that because we will write some React components using JSX. Typically, we’d import the entire React library when making React components. However, wp-element is an abstraction layer atop React so we never have to install or import React directly. Instead, we use wp-element as a global variable.

These packages are also available as npm packages. Instead of importing functions from the global wp variable (which will only be available in the browser that your code editor knows nothing about), we can simply install these packages using npm and import them in our file. These WordPress packages are usually prefixed with @wordpress.

Let’s install the two packages that we need:

npm install @wordpress/edit-post @wordpress/plugins @wordpress/i18n --save

Now we can import our packages in index.js:

import { registerPlugin } from "@wordpress/plugins"; import { PluginSidebar } from "@wordpress/edit-post"; import { __ } from "@wordpress/i18n";

The advantage of importing the packages this way is that your text editor knows what @wordpress/edit-post and @wordpress/plugins are and it can autocomplete functions and components for you — unlike importing from wp.plugins and wp.editPost which will only be available in the browser while the text editor has no clue what wp is.

Your text editor can autocomplete component names for you.

You might also think that importing these packages in your bundle will increase your bundle size, but there’s no worries there. The webpack config file that comes with @wordpress/scripts is instructed to skip bundling these @wordpress packages and depend of the wp global variable instead. As a result, the final bundle will not actually contain the various packages, but reference them via the wp variable.

Great! so I am going to stick to importing packages using npm in this article, but you are totally welcome to import from the global wp variable if you prefer. Let’s now use the functions that we imported!

Registering a Gutenberg Plugin

In order to add a new custom sidebar in Gutenberg, we first need to register a plugin — and that’s what the registerPlugin function that we imported will do. As a first argument, registerPlugin will receive a unique slug for this plugin. We can have an array of options as a second argument. Among these options, we can have an icon name (from the dashicons library) and a render function. This render function can return some components from the wp-edit-post package. In our case. we imported the PluginSidebar component from wp-edit-post and created a sidebar in the Gutenberg editor by returning this component in the render function. I also added PluginSidebar inside a React fragment since we can add other components in the render function as well. Also, the __ function imported from wp-i18n will be used so we can translate any string that we output:

registerPlugin( 'myprefix-sidebar', { icon: 'smiley', render: () => { return ( <> <PluginSidebar title={__('Meta Options', 'textdomain')} > Some Content </PluginSidebar> </> ) } })

You should now have a new icon beside the cog icon in the Gutenberg editor screen. This smiley icon will toggle our new sidebar which will have whatever content we have inside the PluginSidebar component:

If you were to click on that star icon beside the sidebar title, the sidebar smiley icon will be removed from the top toolbar. Therefore, we need to add another way to access our sidebar in case the user un-stars it from the top toolbar, and to do that, we can import a new component from wp-edit-post called PluginSidebarMoreMenuItem. So, let’s modify out import statement:

import { PluginSidebar, PluginSidebarMoreMenuItem } from "@wordpress/edit-post";

The PluginSidebarMoreMenuItem will allow us to add an item in the Gutenberg menu that you can toggle using the three dots icon at the top-right of the page. We want to modify our plugin to include this component. We need to give PluginSidebar a name prop and give PluginSidebarMoreMenuItem a target prop with the same value:

registerPlugin( 'myprefix-sidebar', { icon: 'smiley', render: () => { return ( <> <PluginSidebarMoreMenuItem target="myprefix-sidebar" > {__('Meta Options', 'textdomain')} </PluginSidebarMoreMenuItem> <PluginSidebar name="myprefix-sidebar" title={__('Meta Options', 'textdomain')} > Some Content </PluginSidebar> </> ) } })

In the menu now, we will have a "Meta Options" item with our smiley icon. This new item should toggle our custom sidebar since they are linked using the name and the target props:

Great! Now we have a new space in our Gutenberg page. We can replace the "some content" text in PluginSidebar and add some React components of our own!

Also, let’s make sure to check the edit-post package documentation. This package contains a lot of other components that you can add in your plugin. These components can allow you to extend the existing default sidebar and add your own components in it. Also, we can find components that allow us to add items in the Gutenberg top-right menu and also for the blocks menu.

Handling metadata in the classic editor

Let’s take a quick look at how we used to manage metadata in the classic editor using metaboxes. First, install and activate the classic editor plugin in order to switch back to the classic editor. Then, add some code that will add a metabox in the editor page. This metabox will manage a custom field that we’ll call _myprefix_text_metafield. This metafield will just be a text field that accepts HTML markup. You can add this code in plugin.php or put it in a separate file and include it plugin.php:

<?php function myprefix_add_meta_box() { add_meta_box( 'myprefix_post_options_metabox', 'Post Options', 'myprefix_post_options_metabox_html', 'post', 'normal', 'default' ); } add_action( 'add_meta_boxes', 'myprefix_add_meta_box' ); function myprefix_post_options_metabox_html($post) { $field_value = get_post_meta($post->ID, '_myprefix_text_metafield', true); wp_nonce_field( 'myprefix_update_post_metabox', 'myprefix_update_post_nonce' ); ?> <p> <label for="myprefix_text_metafield"><?php esc_html_e( 'Text Custom Field', 'textdomain' ); ?></label> <br /> <input class="widefat" type="text" name="myprefix_text_metafield" id="myprefix_text_metafield" value="<?php echo esc_attr( $field_value ); ?>" /> </p> <?php } function myprefix_save_post_metabox($post_id, $post) { $edit_cap = get_post_type_object( $post->post_type )->cap->edit_post; if( !current_user_can( $edit_cap, $post_id )) { return; } if( !isset( $_POST['myprefix_update_post_nonce']) || !wp_verify_nonce( $_POST['myprefix_update_post_nonce'], 'myprefix_update_post_metabox' )) { return; } if(array_key_exists('myprefix_text_metafield', $_POST)) { update_post_meta( $post_id, '_myprefix_text_metafield', sanitize_text_field($_POST['myprefix_text_metafield']) ); } } add_action( 'save_post', 'myprefix_save_post_metabox', 10, 2 );

I am not going to go into details in this code since this is out of the scope of the article, but what it’s essentially doing is:

  • Making a metabox using the add_meta_box function
  • Rendering an HTML input using the myprefix_post_options_metabox_html function
  • Controlling the metafield, called _myprefix_text_metafield
  • Using the save_post action hook to get the HTML input value and update the field using update_post_meta.

If you have the classic editor plugin installed, then you should see the metafield in the post editor:

Note that the field is prefixed with an underscore (_myprefix_text_metafield) which prevents it from being edited using the custom fields metabox that comes standard in WordPress. We add this underscore because we intend to manage the field ourselves and because it allows us to hide it from the standard Custom Fields section of the editor.

Now that we have a way to manage the field in the classic editor, let’s go ahead and deactivate the classic editor plugin and switch back to Gutenberg. The metabox will still appear in Gutenberg. However, as we discussed earlier, WordPress recommends porting this PHP-based metabox using a JavaScript approach.

That’s what we will do in the rest of the article. Now that we know how to use the Redux-like stores to manipulate data and how to add some React content in the sidebar, we can finally create a React component that will manipulate our metafield and add it in the sidebar of the Gutenberg editor.

We don’t want to completely get rid of the PHP-based field because it’s still helpful in the event that we need to use the classic editor for some reason. So, we’re going to hide the field when Gutenberg is active and show it when the classic editor is active. We can do that by updating the myprefix_add_meta_box function to use the __back_compat_meta_box option:

function myprefix_add_meta_box() { add_meta_box( 'myprefix_post_options_metabox', 'Post Options', 'myprefix_post_options_metabox_html', 'post', 'normal', 'default', array('__back_compat_meta_box' => true) ); }

Let’s move on to creating the React component that manages the metadata.

Getting and setting metadata using JavaScript

We have seen how to get the post title and how to change it using the wp-data module. Let’s take a look at how to do the same for custom fields. To get metafields, we can call the save selector getEditedPostAttribute. But this time we will pass it a value of meta instead of title.

Once that’s done, test it out in the browser console:

wp.data.select('core/editor').getEditedPostAttribute('meta')

As you will see, this function will return an empty array, although we are sure that we have a custom field called _myprefix_text_metafield that we are managing using the classic editor. To make custom fields manageable using the data module, we first have to register the field in the plugin.php.

function myprefix_register_meta() { register_meta('post', '_myprefix_text_metafield', array( 'show_in_rest' => true, 'type' => 'string', 'single' => true, )); } add_action('init', 'myprefix_register_meta');

Make sure to set the show_in_rest option to true. WordPress will fetch the fields using the WP REST API. That means, we need to enable the show_in_rest option to expose it.

Run the console test again and we will have an object with all of our custom fields returned.

Amazing! We are able to get our custom field value, so now let’s take a look at how can we change the value in the store. We can dispatch the editPost action in the core/editor store and pass it an object with a meta key, which will be another object with the fields that we need to update:

wp.data.dispatch('core/editor').editPost({meta: {_myprefix_text_metafield: 'new value'}})

Now try running the getEditedPostAttribute selector again and the value should be updated to new value.

If you try saving a post after updating the field using Redux, you will get an error. And if you take a look at the Network tab in DevTools, you will find that the error is returned from the wp-json/wp/v2/posts/{id} REST endpoint that says that we are not allowed to update _myprefix_text_metafield.

This because WordPress treats any field that is prefixed with an underscore as a private value that cannot be updated using the REST API. We can, however, specify an auth_callback option that will allow updating this field using the REST API when it returns true as long as the editor is capable of editing posts. We can also add the sanitize_text_field function to sanitize the value before saving to the database:

function myprefix_register_meta() { register_meta('post', '_myprefix_text_metafield', array( 'show_in_rest' => true, 'type' => 'string', 'single' => true, 'sanitize_callback' => 'sanitize_text_field', 'auth_callback' => function() { return current_user_can('edit_posts'); } )); } add_action('init', 'myprefix_register_meta');

Now try the following:

  • Open a new post in WordPress.
  • Run this in the DevTools console see the current value of the field:
wp.data.select('core/editor').getEditedPostAttribute('meta')
  • Run this in DevTools to update the value:
wp.data.dispatch('core/editor').editPost({meta: {_myprefix_text_metafield: 'new value'}})
  • There will be errors, so save the post to clear them.
  • Refresh the page and run this in the DevTools console:
wp.data.select('core/editor').getEditedPostAttribute('meta')

Does the new value show up in the console? If so, great! Now we know how to get and set the meta field value using Redux and we are ready to create a react component in the sidebar to do that.

Creating a React component to manage the custom fields

What we need to do next is create a React component that contains a text field that is controlled by the value of the metafield in the Redux store. It should have the value of the meta field...and hey, we already know how to get that! We can create the component in a separate file and then import it index.js. However I am simply going to create directly in index.js since we’re dealing with a very small example.

Again, we’re only working with a single text field, so let’s import a component provided by a WordPress package called @wordpress/components. This package contains a lot of reusable components that are Gutenberg-ready without us having to write them from scratch. It’s a good idea to use components from this package in order to be consistent with the rest of the Gutenberg UI.

First, let’s install this package:

npm install --save @wordpress/components

We’ll import TextControl and PanelBody at the top of index.js to fetch the two components we need from the package:

import { PanelBody, TextControl } from "@wordpress/components";

Now let’s create our component. I am going to create a React functional component and call it PluginMetaFields, but you can use a class component if you’d prefer that.

let PluginMetaFields = (props) => { return ( <> <PanelBody title={__("Meta Fields Panel", "textdomain")} icon="admin-post" intialOpen={ true } > <TextControl value={wp.data.select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield']} label={__("Text Meta", "textdomain")} /> </PanelBody> </> ) }

PanelBody takes title, icon and initialOpen props. Title and icon are pretty self-explanatory. initialOpen puts the panel in an open/expanded state by default. Inside the panel, we have TextControl. which receives a label and a value for the input. As you can see in the snippet above, we get the value from the global store by accessing the _myprefix_text_metafield field from the object returned by wp.data.select('core/editor').getEditedPostAttribute('meta').

Notice that we are now depending on @wordpress/components and use wp.data. We must add these packages as dependencies when we enqueue our file in plugin.php:

function myprefix_enqueue_assets() { wp_enqueue_script( 'myprefix-gutenberg-sidebar', plugins_url( 'build/index.js', __FILE__ ), array( 'wp-plugins', 'wp-edit-post', 'wp-element', 'wp-components', 'wp-data' ) ); } add_action( 'enqueue_block_editor_assets', 'myprefix_enqueue_assets' );

Let’s officially add the component to the sidebar instead of the dummy text we put in earlier as a quick example:

registerPlugin( 'myprefix-sidebar', { icon: 'smiley', render: () => { return ( <> <PluginSidebarMoreMenuItem target="myprefix-sidebar" > {__('Meta Options', 'textdomain')} </PluginSidebarMoreMenuItem> <PluginSidebar name="myprefix-sidebar" title={__('Meta Options', 'textdomain')} > <PluginMetaFields /> </PluginSidebar> </> ) } })

This should should give you a "Meta Options" panel that contains a "Meta Fields" title, a pin icon, and a text input with a "Test Meta" label and default value of "new value."

Nothing will happen when you type into the text input because we are not yet handling updating the field. We’ll do that next, however, we first need to take care of another problem. Try to run editPost in the DevTools console again, but with a new value:

wp.data.dispatch('core/editor').editPost({meta: {_myprefix_text_metafield: 'a newer value'}})

You will notice that the value in the text field will not update to the new value. That’s the problem. We need the field to be controlled by the value in the Redux store, but we don’t see that reflected in the component. What’s up with that?

If you have used Redux with React before, then you probably know that we need to use a higher order component called connect in order to use Redux store values in a React component. The same goes for React components in Gutenberg — we have to use some higher order component to connect our component with the Redux-like store. Unfortunately, we are unable to simply call wp.data.select directly as we did before. This higher order component lives in the wp.data global variable which is also available as an npm package called @wordpress.data. So let’s install it to help us solve the issue.

npm install --save @wordpress/data

The higher order component we need is called withSelect, so let’s import it in index.js.

import { withSelect } from "@wordpress/data";

Remember that we already added wp-data as a dependency in wp_enqueue_script, so we can just use it by wrapping our component with it, like so:

PluginMetaFields = withSelect( (select) => { return { text_metafield: select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield'] } } )(PluginMetaFields);

Here, we’re overriding our PluginMetaFields component and assigning it the same component, now wrapped with the withSelect higher order component. withSelect will receive a function as an argument. This function will receive the select function (which we used to access wp.data.select) and it should return an object. Each key in this object will be injected as a prop in the component (similar to connect in Redux). withSelect will return a function that we can pass it the component (PluginMetaFields) again as seen above. So, by having this higher order component, we now get text_metafield as a prop in the component, and whenever the meta value in the redux store is updated, the prop will also get updated — thus, the component will update since components update whenever a prop is changed.

let PluginMetaFields = (props) => { return ( <> <PanelBody title={__("Meta Fields Panel", "textdomain")} icon="admin-post" intialOpen={ true } > <TextControl value={props.text_metafield} label={__("Text Meta", "textdomain")} /> </PanelBody> </> ) }

If you now try and run editPost with a new meta value in your browser, the value of the text field in the sidebar should also be updated accordingly!

So far, so good. Now we know how to connect our React components with our Redux-like stores. We are now left with updating the meta value in the store whenever we type in the text field.

Dispatching actions in React components

We now need to dispatch the editPost action whenever we type into the text field. Similar to wp.data.select, we also should not call wp.data.dispatch directly in our component like so:

// Do not do this <TextControl value={props.text_metafield} label={__("Text Meta", "textdomain")} onChange={(value) => wp.data.dispatch('core/editor').editPost({meta: {_myprefix_text_metafield: value}}) } />

We will instead wrap our component with another higher order component from the @wordpress.data package called withDispatch. We’ve gotta import that, again, in plugin.js:

import { withSelect, withDispatch } from "@wordpress/data";

In order to use it, we can wrap our component — which is already wrapped with withSelect and again with withDispatch — like so:

PluginMetaFields = withDispatch( (dispatch) => { return { onMetaFieldChange: (value) => { dispatch('core/editor').editPost({meta: {_myprefix_text_metafield: value}}) } } } )(PluginMetaFields);

You can check out yet another WordPress package called @wordpress/compose. It makes using multiple high order components a bit cleaner for use in a single component. But I will leave that to you to try out for the sake of keeping our example simple.

withDispatch is similar to withSelect in that it will receive a function that has the dispatch function as an argument. That allows us to return an object from this function that contains functions that will be available inside the component’s props. I went about this by creating a function with an arbitrary name (onMetaFieldChange) that will receive a value, dispatch the editPost action, and set the meta value in the Redux store to the value received in the function’s argument. We can call this function in the component and pass it the value of the text field inside the onChange callback:

<TextControl value={props.text_metafield} label={__("Text Meta", "textdomain")} onChange={(value) => props.onMetaFieldChange(value)} />

Confirm everything is working fine by opening the custom sidebar in the WordPress post editor, updating the field, saving the post and then refreshing the page to make sure the value is saved in the database!

Let’s add a color picker

It should be clear now that can we update a meta field using JavaScript, but we’ve only looked at simple text field so far. The @wordpress/components library provides a lot of very useful components, including dropdowns, checkboxes, radio buttons, and so on. Let’s level up and conclude this tutorial by taking a look at how we can use the color picker component that’s included in the library.

You probably know what to do. First, we, import this component in index.js:

import { PanelBody, TextControl, ColorPicker } from "@wordpress/components";

Now, instead of registering a new custom field, let’s aim for simplicity and assume that this color picker will be controlled by the same _myprefix_text_metafield field we worked with earlier. We can use the ColorPicker component inside our PanelBody and it will be very similar to what we saw with TextControl, but the prop names will be slightly different. We have a color prop instead of value and onChangeComplete instead on onChange. Also, onChangeComplete will receive a color object that contains some information about the chosen color. This object will have a hex property we can use to store the color value in the _myprefix_text_metafield field.

Catch all that? It boils down to this:

<ColorPicker color={props.text_metafield} label={__("Colour Meta", "textdomain")} onChangeComplete={(color) => props.onMetaFieldChange(color.hex)} />

We should now have a color picker in our sidebar, and since it’s controlling the same meta field as the TextControl component, our old text field should update whenever we pick a new color.

That’s a wrap!

If you have reached this far in the article, then congratulations! I hope you enjoyed it. Make sure to check out my course if you want to learn more about Gutenberg and custom blocks. You can also find the final code for this article over at GitHub.

The post Managing WordPress Metadata in Gutenberg Using a Sidebar Plugin appeared first on CSS-Tricks.

So, you think you’ve got project management nailed down

Css Tricks - Thu, 06/20/2019 - 5:04am

(This is a sponsored post.)

Who needs a project manager? You're an organized person who can keep track of your own work, right?

Wrong.

Well, wrong if you're part of a team. The thing about being self-organized is that it's related to project management but not synonymous with it. Case in point: what happens if your project relies on someone else's involvement? Sure you're organized, but can you always say the same about your co-workers? Chances are you need something to keep everyone in sync so that a project stays on course.

That's where you should consider trying monday.com.

monday.com is project management, but with a human touch. Sure, there's task lists, assignments, milestones, due dates, and such like you would expect from any project management tool. That's a given. That said, monday.com takes things up a notch by stripping away the barriers that prevent team members from collaborating with one another. For example, monday.com includes real-time messaging, file sharing, reporting, and a slew of other features that bridge the gaps between people and tasks so that everyone has purview into the progress of a project. Plus, it's so pretty to look at.

There's so much more than meets the eye because monday.com goes beyond project management. There's resource management that ensures you have the right tools for a project, forecasting to affirm the prospect of a business opportunity, and even client management services. Seriously, your team and perhaps company can lean into monday.com and get a ton of use out of it.

You know what to do from here. Give monday.com a try. There's a free trial and we're sure you'll find it to be so useful that you'll want to stick with it well beyond.

Get Started

Direct Link to ArticlePermalink

The post So, you think you’ve got project management nailed down appeared first on CSS-Tricks.

How to Increase Your Page Size by 1,500% with webpack and Vue

Css Tricks - Wed, 06/19/2019 - 4:25am

Disclaimer: This article is mostly satire. I do not think that I am better than you because I once wrote some TypeScript nor do I think that it’s a good thing for us to make web pages bigger. Feel free to misrepresent these views to maximize clicks.

You know, there are a lot of articles out there telling you how to make your page smaller: optimize your images, remove extraneous CSS rules, re-write the whole thing in Dreamweaver using framesets. Look, ?Walmart just reduced their page size by some numbers, give or take.

JavaScript housekeeping:

&#x1f5d1;️ Remove old & duplicate deps
&#x1f425; Replace large deps w/small ones
&#x1f9d0; Check you aren't over-polyfilling
&#x1f9fd; Clean up A/B test configs
✂️ Code-splitting!

Walmart Grocery did this for their site. 69% smaller JS bundles. 28% faster Time-to-Interactive. pic.twitter.com/3kSp7Ssi35

— Addy Osmani (@addyosmani) May 31, 2019

What we don’t have are enough articles showing you how to increase your page size. In fact, the only article I could find was this one from the Geek Squad which ended up being about making the font size bigger. This is a good start, but I think we can do better.

Put on some weight

Now, why would you want to increase your page size? Isn’t that a not-very-nice thing for people on low bandwidth connections? Well, there are several excellent and in no-way-contrived reasons and here are three of them since things that come in threes are more satisfying.

  1. You have a gigabit connection and you live in Tennessee so surely everyone else is in better shape than you are.
  2. Browsers do caching, silly. That means that you only have to download the site once. Stop complaining. First world problems.
  3. You don’t care whether or not people ever visit your site because you, "work to live, not live to work."

If any of those completely relatable reasons resonates with you, I’d like to show you how I increased the size of my CSS by 1,500% — and you can too, with one simple webpack trick.

One weird trick

It all started when I decided to refactor my retirement plan project called The Urlist over to the Bulma CSS framework.

The original incarnation of the site was all hand-rolled and my Sass looked like an episode of Hoarders.

"Burke, you don’t need 13 different .button styles. Why don’t you pick one and we can get rid of these other 12 so you have somewhere to sleep?"

Bulma also includes things like modals that I used third-party Vue components to make.

It also has a hamburger menu because it’s a well-known scientific fact that you cannot have a successful site without a hamburger.

Look,?I don’t make the rules. This is just how business works.

I was quite happy with the result. Bulma styles are sharp, and the layout system is easy to learn. It’s almost as if someone somewhere understands CSS and also doesn’t hate me. That’s just a hard combination to find these days.

After a few weeks of refactoring (during which I would ask myself, "WHAT ARE YOU EVEN DOING MAN?!? THE SITE ALREADY WORKS!"), I finally finished. As a side note, the next time you think about refactoring something, don’t. Just leave it alone. If you don’t leave any technical debt for the next generation, they’re going to be extremely bored and that’s going to be on you.

When I built the project, I noticed something odd: the size of my CSS had gone up pretty significantly. My hand-crafted abomination was only 30KB gzipped and I was up to 260KB after the refactor.

And, to make matters worse, the Vue CLI was lecturing me about it...

Which, of course, I ignored. I don’t take instructions from robots.

What I did instead was deploy it. To production. On the internet. Because I did not spend all of this time refactoring to not deploy it. Yeah, sunk costs and all that, but excuse me if I’m more pragmatic than your poster of logical fallacies. All I’m saying is I came to party and I was not going home without a buzz.

Then I took to Twitter to announce my accomplishment to the ambivalent masses. As one does.

I refactored https://t.co/hgGmemoQeX to Bulma. The whole thing looks cleaner and the styles are drastically simplified. Great work, @jgthms.

Only downside is that my CSS is now pretty big. ~260kb gzipped. Before it was ~30kb. Worth the trade-off? pic.twitter.com/te2DTgknS1

— Burke Holland (@burkeholland) May 28, 2019

Shortly thereafter, Jeremy Thomas, who created Bulma (and clearly loves Dragon Ball) responded. It was quick, too. It’s like there is a bat signal that goes out whenever a moron tweets.

Nice! It seems your CSS got big because of lots of duplicate styles.
For example, ".section.is-medium[data-v-" is in the CSS 13 times, but should only be there once. Same if your search for ".hero[data-v-".
It seems you've namespaced the whole of Bulma in each of your component.

— Jeremy Thomas (@jgthms) May 28, 2019

Duplicate styles? 13 times? What the heck is a namespace? Is that a ? symbol or a custom Jeremy Thomas logo?

It’s at this moment that I realized that I have no idea what I’m doing.

Put the Sass down and back away slowly

I’ll be the first to admit that I don’t know a lot about CSS, and even Less about Sass. Get it? Less about Sass? Forget it. I don’t want your pity laugh.

When I setup my Vue CLI project to use Bulma, I created a src/styles folder and dropped in a bulma-but-not-all-of-bulma-only-some-of-it.scss file. They say naming things is hard, but I don’t see why.

That file imports the pieces of Bulma that I want to use. It’s Bulma, but not all of it. Only some of it.

@import "bulma/sass/utilities/_all.sass"; @import "bulma/sass/base/_all.sass"; @import "bulma/sass/form/shared.sass"; @import "bulma/sass/form/input-textarea.sass"; // etc...

Then I imported that file into a custom Sass file which I called... site.scss. I like to keep things simple.

@import "./bulma-but-not-all-of-bulma-only-some-of-it.scss"; html, body { background-color: #f9fafc; } // etc...

I wanted to import these files into Vue globally so that I could use them in every component. And I wanted to do it the right way; the canonical way. I think it’s clear from my willingness to deploy 2+ MB of CSS into production that I like to do things the "right way".

I read this excellent blog post from Sarah Drasner called, "How to import a Sass file into every component in your Vue app." She shows how to do it by modifying the webpack build process via the vue.config.js file.

module.exports = { css: { loaderOptions: { sass: { data: `@import "@/styles/site.scss";` } } } }

What I did not understand is that this imports Sass into every component in a Vue app. You know, like the title of the blog post literally says. This is also how I ended up with a bunch of duplicate styles that had a data-v- attribute selector on them. I have scoped styles to thank for that.

How Vue handles `scoped`

Vue allows you to "scope" styles to a component. This means that a style only affects the component that it’s in, and not the rest of the page. There is no magic browser API that does this. Vue pulls it off by dynamically inserting a data- attribute in both the element and the selector. For example, this:

<template> <button class="submit">Submit</button> <template> <style lang="scss" scoped> .submit { background-color: #20ae96; } </style>

...becomes this:

<button class="submit" data-v-2929>Submit</button> <style> .submit[data-v-2929] { background-color: #20ae96; } </style>

That dynamic data tag gets added to every child element in the component as well. So every element and every style for this component will have a data-v-2929 on them at runtime.

If you import a Sass file into your component that has actual styles in it, Vue (via webpack) will pull in those styles and "namespace" them with that dynamic data- attribute. The result is that is you include Bulma in your app 13 damn times with a bunch of data-v weirdness in front of it.

But this begs the question: if webpack renders the CSS in every single component, why would you ever want to use the vue.config.js approach? In a word: variables.

The variable sharing problem

You can’t define a Sass variable in one component and reference it from another. That would also be kind of hard to manage since you would be defining and using variables all over the place. Only I would write code like that.

You, on the other hand, would probably put all your variables in a variables.scss file. Each component would then reference that central store of variables. Importing a variables file into every single component is redundant. It’s also excessive. And unnecessary. And long-winded.

This is precisely the problem that Sarah’s article is solving: importing a Sass file into every component in your project.

It’s OK to import something like variables into every component because variables aren’t rendered. If you import 200 variables and only reference one of them, who cares? Those variables don’t exist in the rendered CSS anyway.

For example, this:

<style lang="scss" scoped> $primary: #20ae96; $secondary: #336699; .submit { background-color: $primary } </style>

...becomes this:

<style> .submit[data-v-2929] { background-color: #20ae96; } </style>

So, there are really two problems here:

  1. Bulma needs to be global.
  2. Bulma’s variables should be accessible from the components.

What we need is a clever combination of Sarah’s technique, along with a little proprietary knowledge about how Bulma is structured.

Using Bulma with the Vue

We’re going to accomplish this with the least amount of duplication by having three files in the src/styles directory:

variables.scss: This file will be where you pull in Bulma’s variables and override/define your own. Note that you have to include the following three files to get all of Bulma’s variables. And they have to be in this order...

// Your variables customizations go up here // Include Bulma's variables @import "bulma/sass/utilities/initial-variables.sass"; @import "bulma/sass/utilities/functions.sass"; @import "bulma/sass/utilities/derived-variables.sass";

bulma-custom.scss: This file is where you pull in the pieces of Bulma that you want. It should reference the variables.scss file.

@import "./variables.scss"; /* UTILTIES */ @import "bulma/sass/utilities/animations.sass"; @import "bulma/sass/utilities/controls.sass"; @import "bulma/sass/utilities/mixins.sass"; // etc...

site.scss: This pulls in the bulma-custom.scss file and is also where you define global styles that are used across the whole project.

@import url("https://use.fontawesome.com/releases/v5.6.3/css/all.css"); @import "./bulma-custom.scss"; html, body { height: 100%; background-color: #f9fafc; } // etc...

Import the site.scss file into your main.js file. Or in my case, main.ts. Does it make me better than you that I use TypeScript? Yes. Yes it does.

import Vue from "vue"; import App from "./App.vue"; import router from "./router"; // import styles import "@/styles/site.scss";

This makes all of the Bulma pieces we are using available in every component. They are global, but only included once.

Per Sarah’s article, add the variables.scss file to the vue.config.js file.

module.exports = { css: { loaderOptions: { sass: { data: `@import "@/styles/variables.scss";` } } } }

This makes it so that you can reference any of the Bulma variables or your own from any .vue component.

Now you have the best of both worlds: Bulma is available globally and you still have access to all Bulma variables in every component.

Total size of CSS now? About 1,500% smaller...

Take that, Walmart.

Redemption via PR

In an effort to redeem myself, I’ve submitted a PR to the Bulma docs that walks through how to customize Bulma in a Vue CLI project. It’s an act of contrition for taking to Twitter and making Bulma seem like the problem when really Burke is the problem.

And you would think that by now I would have this figured out: Burke is always the problem.

The post How to Increase Your Page Size by 1,500% with webpack and Vue appeared first on CSS-Tricks.

Drop caps & design systems

Css Tricks - Wed, 06/19/2019 - 4:25am

Ethan Marcotte has written up his process for how to make drop caps accessible for screen readers and browsers alike. All of that is very interesting and I’m sure I’ll use a technique like this in the near future, but the part that made me hop out of my seat is where Ethan notes his experience with design systems at Vox:

Since rolling out our new and improved drop caps, we’ve continued to iterate on them. (Including fixing a number of bugs that I, a professional web designer, introduced.) We’ve also discussed potential changes to the custom styles feature, in order to make it sustainable. But for my money, the real benefit of the work wasn’t the drop caps themselves, but the process that emerged from it.

This is something I’ve been thinking about a lot. The tricky thing to understanding design systems is that the process of creating and maintaining them is just as important than the code it uses. Sure, yes, fixing small things is very important, but the long-lasting improvements to a design system will always be around process. Why is this thing breaking? How long has it been broken for? How do we setup a way to make sure that this problem never pops up again?

Questions about process will always be the most useful questions to ask. The system will reward you for asking.

Direct Link to ArticlePermalink

The post Drop caps & design systems appeared first on CSS-Tricks.

Every Layout

Css Tricks - Tue, 06/18/2019 - 11:57am

Every Layout is a new work-in-progress website and book by Heydon Pickering and Andy Bell that explains how to make common layout patterns with CSS. They describe a lot of the issues when it comes to the design of these layouts, such as responsive problems and making sure we all write maintainable code, and then they’ve provided a handy generator at the end of each article to create our own little frameworks for dealing with these things.

They also have a complementary blog and one of the posts called "Algorithmic Design" caught my eye:

We make many of our biggest mistakes as visual designers for the web by insisting on hard coding designs. We break browsers’ layout algorithms by applying fixed positions and dimensions to our content.

Instead, we should be deferential to the underlying algorithms that power CSS, and we should think in terms of algorithms as we extrapolate layouts based on these foundations. We need to be leveraging selector logic, harnessing flow and wrapping behavior, and using calculations to adapt layout to context.

The tools for flexible, robust, and efficient web layout are there. We are just too busy churning out CSS to use them.

I’m looking forward to seeing where this project goes and how many more layouts these two end up documenting.

Direct Link to ArticlePermalink

The post Every Layout appeared first on CSS-Tricks.

How to Section Your HTML

Css Tricks - Tue, 06/18/2019 - 4:22am

It has been brought to our attention in the comments that some of the techniques used in this article result in a poor user experience for screen reader users. Daniel has updated the post accordingly with alternate markup in several of the examples and demos. We'll continue to make edits to address other things that others have noticed. Thanks for being such an awesome community where we can all learn and grow together.

The sectioning elements in HTML5 are <nav>, <aside>, <article>, and <section>. <body> is also kind of a sectioning element since all content lying inside of it is part of the default document section.

Here is a brief explanation of each sectioning element and how they are used:

  • <nav> - Equivalent to role="navigation". Major site navigation that consistently appears frequently across the site. Examples include the primary navigation, secondary navigation, and in-page navigation.
  • <aside> - Equivalent to role="complementary". Content that is only tangentially related (or not related) to the main content. Think of something like a sidebar with supplementary information, a note within an article, or the outer container for a list of related articles at the bottom of a blog post.
  • <article> - Equivalent to role="article". Content that is self-contained in that it makes sense on its own when taken out of context. That could mean a widget, a blog post or even a comment within a blog post.
  • <section> - Equivalent to role="region". Content that needs extra context from its parent sectioning element to make sense. This is a generic sectioning element that is used whenever it doesn’t make sense to use the other more semantic ones.

https://t.co/NAZMrlQ1O5

I added HTML comments with some explanation of changes I made.

— Adrian Roselli &#x1f5ef; (@aardrian) June 20, 2019

See the Pen
Mock up page layout v2 (sections article)
by Adrian Roselli (@aardrian)
on CodePen.

Contents

This is a very long article that I suspect you will want to come back to and reference multiple times. To make that easier, here is a list of all the article headings:

Jump to article heading
  1. When to use <nav>
    1. A <nav> is unnecessary around a search form
    2. Don’t use the word "nav" or "navigation" in the label
    3. Questions to ask yourself
    4. A <nav> doesn’t have to be a list of links
  2. Avoid nesting an <aside> inside an <aside>
  3. Article is like "Block"; Section is like "Element"
    1. Comments sections
  4. Don’t swap <div> for <section>
  5. Headers and footers
    1. What goes inside headers?
    2. What goes inside footers?
  6. Sectioning elements and the document outline algorithm
    1. No browser supports the document outline algorithm
  7. Sectioning content
  8. The <main> element
  9. You need to label your sections. Here are three methods.
    1. Method 1: Add an aria-label attribute
      1. The aria-label translation issue
      2. Positives
      3. Negatives
    2. Method 2: Add a <h#> element to it
      1. Heading placement
      2. Only one heading of the highest level per sectioning element
      3. The heading always comes first
      4. Making visually hidden section labels out of headings
      5. Headings are well-supported by structure analysis tools
      6. Positives
      7. Negatives
    3. Method 3: Use an aria-labelledby attribute
      1. Labels can be hidden without CSS
      2. Major portability issue
      3. No need to place the label near the sectioning element
      4. Turn non-heading elements into section labels
      5. Positives
      6. Negatives
  10. Only use one method at a time
  11. Adding section labels to our example layout
  12. Making Heading 1 be the first heading
  13. Concerns with the simplified outline algorithm spec
  14. Using aria on the example layout sectioning elements
    1. Using aria-label
    2. Using aria-labelledby
    3. Results of using aria
  15. What happens when you need h7?
  16. Does your site have a good structure?
  17. Download and use a screen reader
When to use <nav>

The <nav> element only ever needs to be used once per navigation block. Sub-navigation that is already contained inside a <nav> element does not need to be wrapped in a second <nav> element.

<nav aria-label="Primary"> <ul> <li><a href="#">Primary link</a></li> <li><a href="#">Primary link</a></li> <li> <a href="#">Primary link</a> <!-- <nav> element is *not* needed again here --> <ul> <li><a href="#">Secondary link</a></li> <li><a href="#">Secondary link</a></li> </ul> </li> </ul> </nav>

The <nav> element is intended for only major navigation blocks. "Major" is a very subjective term though. html5doctor.com has a pretty good explanation of when it is and isn’t appropriate to use <nav>, keep in mind that the following are opinions and not official W3C rulings:

The key phrase is ‘major’ navigation. We could debate all day about the definition of ‘major’, but to me it means:

  • Primary navigation
  • Site search
  • Secondary navigation (arguably)
  • In-page navigation (within a long article, for example)

While there isn’t any right or wrong here, a straw poll coupled with my own interpretation tells me that the following shouldn’t be enclosed by <nav>:

  • Pagination controls
  • Social links (although there may be exceptions where social links are the major navigation, in sites like About me or Flavours, for example)
  • Tags on a blog post
  • Categories on a blog post
  • Tertiary navigation
  • Fat footers

html5doctor.com (strikethrough mine)

Breadcrumbs are another piece of content that should be wrapped in a <nav> element as evidenced by this W3C breadcrumb HTML example.

A <nav> is unnecessary around a search form

I disagree with HTML5 Doctor’s opinion that a site search form should be wrapped in a <nav> element (thus why I crossed it out). <nav> is intended to be wrapped around navigation links, not a form. The site search actually has its own special role that defines it as a search landmark. If you add role="search" to the search <form> element, it is announced to screen reader users as a search landmark. Screen reader users will also be able to navigate to it when navigating via landmarks. If there are multiple search forms on the page, they should be differentiated using aria-label or aria-labelledby (more details on these attributes later). Don’t include the word "search" in the aria label though — that’s like saying "image of" in image alt text; it’s unnecessary. Instead, focus on what the search form is searching through. So, for the global site search, giving it aria-label="site" would be appropriate.

<!-- <nav> is not needed on a search form. --> <!-- role="search" is enough --> <form role="search" aria-label="site"> <label> <span>Search</span> <input type="search" /> </label> <buton type="submit">Submit</button> </form>

A role="search" form won’t appear in a document outline but I think this is okay considering search forms are often small and self-contained. It still gets the majority of benefits that you get from using sectioning elements. Adding a sectioning element to the mix bombards the screen reader user with messages telling them that it is a search form (one for the sectioning element, one for the search role, and one for the search input label).

Don’t use the word "nav" or "navigation" in the label

Like with role="search", adding "navigation" to the label of a <nav> element only results in a screen reader saying "navigation" twice.

<nav aria-label="primary navigation"> <!-- Screen reader: "primary navigation navigation landmark" --> </nav> <nav aria-label="primary"> <!-- Screen reader: "primary navigation landmark" --> </nav> Questions to ask yourself

That same HTML5 Doctor article lists two questions that you can ask yourself to help you figure out if something should be wrapped in a <nav> or not:

  • Would another sectioning element also be appropriate? If yes, maybe use that instead.
  • Would you add a link to it in a "skip to" block for accessibility? If not, then it might not be worth using a <nav> element.

In those cases where the navigation is too minor to justify the use of the <nav> element, <section> is most likely the element that you should use instead.

A <nav> doesn’t have to be a list of links

The most common use case for a <nav> is to wrap it around a list of links but it doesn’t have to be a list of links. If your navigation works in a different sort of way, you can still use the <nav> element.

<!-- Example taken from the <nav> element specification --> <!-- https://html.spec.whatwg.org/multipage/sections.html#the-nav-element:the-nav-element-5 --> <nav> <h1>Navigation</h1> <p>You are on my home page. To the north lies <a href="/blog">my blog</a>, from whence the sounds of battle can be heard. To the east you can see a large mountain, upon which many <a href="/school">school papers</a> are littered. Far up thus mountain you can spy a little figure who appears to be me, desperately scribbling a <a href="/school/thesis">thesis</a>.</p> <p>To the west are several exits. One fun-looking exit is labeled <a href="https://games.example.com/">"games"</a>. Another more boring-looking exit is labeled <a href="https://isp.example.net/">ISP&#x2122;</a>.</p> <p>To the south lies a dark and dank <a href="/about">contacts page</a>. Cobwebs cover its disused entrance, and at one point you see a rat run quickly out of the page.</p> </nav>

In this same vein, it’s okay to have small bits like intro text in the <nav> element as long as the primary focus of the content is on the navigation links. Introductory content is best placed inside a <header> in the <nav> element. I’ll go into more depth on headers and footers later.

<nav> <header> <h2>In this section</h2> <p>This is some intro text describing what you will find in this section.</p> </header> <ul> <li><a href="#">Sub section one</a></li> <li><a href="#">Sub section two</a></li> </ul> </nav> Avoid nesting an <aside> inside an <aside>

In the same way that <nav> shouldn’t really ever be nested inside another <nav> element, <aside> elements also tend not to be nested inside each other. <aside> is used to represent content that is tangentially related to the content around it. That means placing an aside inside an aside is basically announcing a tangent away from something that in itself is a tangent away from the main content.

<!-- Don't do this --> <aside aria-label="Side bar"> <aside> <h2>Share</h2> <ul> <!-- List of social media links --> </ul> </aside> <aside> <h2>Recommendations:</h2> <ul> <li> <article> <h2><a href="#">Related article title</a></h2> <p>Article description</p> </article> </li> <!-- List of recommended articles continues --> </ul> </aside> </aside>

If you have a sidebar that has multiple sections, don’t nest <aside> elements inside of <aside> elements like in the example above. Instead, make the sidebar a single <aside> and then use <section> (or another appropriate sectioning element) to create the different sections.

<!-- Do this instead --> <aside aria-label="Side bar"> <section> <h2>Share</h2> <ul> <!-- List of social media links --> </ul> </section> <section> <h2>Recommended articles:</h2> <ul> <li> <article> <h2><a href="#">Related article title</a></h2> <p>Article description</p> </article> </li> <!-- List of recommended articles continues --> </ul> </section> </aside> Article is like "Block"; Section is like "Element"

<section> and <article> are easy to get confused with one another. If you are familiar with "Block Element Modifier" (BEM) syntax, then an easy way to think of the difference between the two is that an <article> is a bit like the "B" (or "Block") in BEM. It is a container that stores self-contained content that still makes sense when placed in a different context. Individual tweets on Twitter and each list item on a search results page would be considered <article> elements.

<section> is like the "E" (or "Element") in BEM. It is a sub-section that requires context from its parent sectioning element to make sense. <section> is a generic catch-all sectioning element that you use when it doesn’t make sense to use the other sectioning elements. So, if in doubt, go with <section>.

Note that if something is styled as a "Block" in BEM, that doesn't automatically mean that it is an <article> element. Same goes for BEM "Elements" and <section> elements. The element of something should be based on the meaning of the content, not how the content looks.

Comments sections

Something that may surprise people is that individual comments on a blog post are also considered articles, even though they are in reply to the main blog post. The <article> element wrapping around the main blog post should also wrap around the comments section though. This is to represent that the comments go with the main article.

<article> <h1>I am an awesome blog post!</h1> <p>I am some body text content.</p> <section> <h2>Comments</h2> <ul> <li> <article> <h2>Username</h2> <p>This is the comment body text.</p> <footer> <p> Meta data like post date makes sense in either the header or the footer. </p> </footer> </article> </li> </ul> </section> </article> Don’t swap div for a section

Just because we have these fancy sectioning elements now, it doesn’t mean that the good old <div> element has lost all of its usefulness. <div> has no semantic meaning, so it is quite useful whenever we are altering the HTML purely for the sake of styling purposes.

Let’s say that we have a blog post contained inside an <article> element that we need to wrap in something for the sake of styling purposes.

<!-- I need a wrapper element --> <article> <h1>I am a blog post</h1> <p>I am some content</p> </article>

Reaching for the <section> element in this circumstance is not the right thing to do.

<!-- Do not do this --> <section class="wrapper"> <article> <h1>I am a blog post</h1> <p>I am some content</p> </article> </section>

Though <section> is technically a generic element, <div> is the far more appropriate option in this circumstance. This new wrapping container is not meant to have any semantic meaning behind it and that is exactly what <div> is designed to be used for.

<!-- Use a <div> if the element is only used for styling purposes --> <div class="wrapper"> <article> <h1>I am a blog post</h1> <p>I am some content</p> </article> </div>

Another way to remember this: if you can’t think of a meaningful heading to apply to a <section>, then it probably shouldn’t be a <section>.

Headers and footers

Although they don’t necessarily need to, sectioning elements may contain a single <header> and a single <footer> with the header being at the top of the section and the footer being at the bottom.

Sectioning elements can be nested inside one another as many times as is needed based on the content.

The header and footer in a sectioning element can also contain sectioning elements.

The one major restriction around nesting sectioning elements is that headers and footers cannot be nested inside other headers and footers.

Nesting headers and footers inside one another is not allowed. What goes inside headers?

Headers are used for introductory content. Appropriate things to include in <header> elements include (but are not limited to):

  • The heading element (<h1>-<h6>)
  • An introductory paragraph or statement.
  • A profile picture
  • A logo
  • A search form
  • Primary navigation
  • Author’s name
  • Post/updated date
  • Meta data
  • Social media links
What goes inside footers?

Footer elements primarily hold things like meta data and minor supporting content. Appropriate things to include in <footer> elements include (but are not limited to):

  • Copyright information
  • Legalities
  • Footnotes
  • Low priority site navigation
  • Author’s name
  • Post/updated date
  • Meta data
  • Social media links

You will notice that there is some cross over between the header and the footer in terms of content that is appropriate to both. This is mostly because meta-type content fits well in either element. It mainly comes down to the design that you are trying to achieve. <header> elements do tend to signify that the content inside of them is of greater importance than the content inside of a <footer> element though.

Sectioning elements and the document outline algorithm

An important thing to know about these sectioning elements is that they are all supposed to feature a <h#> element inside of them (or be labeled in some other way, but more on that later). This is primarily for the sake of something called the document outline algorithm. This is an algorithm that uses sectioning elements to help determine what level a heading (<h#>) should be without having to rely exclusively on the number that the developer has provided. So, have you ever wondered whether or not it’s okay to have more than one <h1> on a page? This is meant to make that a non-issue (but hold on for a sec, because there is more to the story).

<!-- No Document outline algorithm --> <article> <h1>Primary heading</h1> <h2>Secondary heading</h2> <p>Some text.</p> <h3>Tertiary heading</h3> <p>Some text.</p> </article> <!-- With document outline algorithm --> <article> <h1>Primary heading</h1> <!-- Recognized as <h1> --> <!-- sectioning element sets new heading level context --> <section> <h1>Secondary heading</h1> <!-- Recognized as <h2> --> <p>Some text.</p> <h2>Tertiary heading</h2> <!-- Recognized as <h3> --> <p>Some text.</p> </section> </article>

There is a lot more to learn about the document outline algorithm. I’ll stop here though because...

No browser supports the document outline algorithm

There is not a single browser that supports this method of creating a heading structure. This is a shame. It would make building accessible websites much easier if we didn’t have to worry so much about using the correct heading level all the time.

As far as I’m aware, there are two main reasons why no browser has implemented the algorithm. One is that browser vendors are afraid of breaking the heading structure of sites that have used sectioning elements incorrectly. The other reason is that the current document outline algorithm spec is difficult to implement and no browser vendor has been willing to put the time into implementing it yet.

In reference to the first reason, there is a long discussion about incorporating a new <h> element instead of using the <h1> element to tell browsers to use the document outline algorithm. I was in favor of this new <h> element idea until I realized that an attribute on the <html> element or adding a <meta> tag to the <head> would work even better as a means of telling browsers it was safe to use the algorithm. It is also better for headings to fall back to a <h1> in unsupported browsers than falling back to a <span>.

If you would like to play around with this <h> concept though, there is a plugin called hfill. It allows you to nest <hx> headings inside sectioning elements to create the document outline without having to worry about heading levels so much. There is a demo available for you to try it out. The major flaw in this plugin though is that the only way to increment heading levels is by nesting sectioning elements inside one another. There is no <h1>-is-greater-than-<h2> dynamic in this plugin which is the main reason I fell out of love with this <h> element idea. This lack of heading hierarchy would make CMS rich text editors far too difficult for clients to use.

As for the issue around implementation difficulty, work is being done to produce a simplified spec that browser vendors are more likely to adopt. The document outline algorithm has been in the HTML specifications for years. Hopefully this simplified spec will allow the algorithm to become a reality.

Although the algorithm is not supported anywhere yet, we can still build with the algorithm in mind. If we build with it in mind, then we gain the following benefits:

  1. We future-proof our sites in case the algorithm ever does get implemented.
  2. We can significantly improve the user experience for screen reader users.
  3. We potentially improve search engine optimization (SEO) due to search engines being able to better understand the site’s content.
  4. We can create a better user experience for users by allowing them to use native browser features that make use of sectioning elements, like Reader Mode.
Sectioning content

Take a look at this mock-up layout I put together and think about how you might split it up into sections.

This is how I would split the layout up into sectioning elements (only the solid lines represent sectioning elements).

In terms of HTML markup, it looks like this:

<body> <header> <a href="/" title="Go to home page"> <img src="logo.png" alt="Site logo"> </a> <nav> <ul> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> </ul> </nav> <form role="search" aria-label="site"> <label> <span>Search</span> <input type="search"/> </label> <button type="submit">Submit</button> </form> </header> <nav> <ul> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> </ul> </nav> <main> <article> <h1>Main article heading</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p> <h2>Article secondary heading</h2> <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p> <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p> </article> </main> <aside> <section> <h2>Share</h2> <ul> <li><a href="#">Facebook</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Email</a></li> </ul> </section> <section> <h2>Recommended</h2> <ul> <li> <article> <h3><a href="#">Related article</a></h3> <p>Article description</p> </article> </li> <li> <article> <h3><a href="#">Related article</a></h3> <p>Article description</p> </article> </li> </ul> </section> </aside> <footer> <ul> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> </ul> </footer> </body> The <main> element

There is a very important semantic element that I used in the markup above that I haven’t covered yet and that is the <main> element. The <main> element represents the primary content of the page. It is not supposed to feature any side bars or navigation elements in it. You also must not have more than one <main> element on the page unless all other <main> elements on the page have a hidden attribute applied to them (this is for the sake of SPAs).

The <main> element is not a sectioning element. This means that it doesn’t help contribute to the document outline algorithm and it can’t feature a <header> or <footer> element as a direct child. It is a landmark element though so screen reader users are able to navigate to it quite easily.

I’m not 100% sure if using <article> in the <main> element like I have done above is necessary. Semantically, it does make sense. The main content is self-contained, thus justifying use of the <article> element in this way. From a document outline algorithm perspective, the <article> element also helps with the document structure.

From a usability point of view, it feels a bit unnecessary and the document outline algorithm doesn’t even work anywhere at the moment. I’m going to continue using it throughout my examples but I would be interested to know what other people think about this in the comments section.

You need to label your sections. Here are three methods.

I am going to be saying the word "label" a lot throughout this article. Keep in mind that I am not talking about the <label> element. The <label> element is not used to label sectioning elements.

Sectioning elements require labels so that screen reader users are able to quickly identify what content they can find inside that particular section of the site. I consider using sectioning elements without providing associated section labels as an accessibility fail, unless it is the only one of its type on the page. It is also recommended that the exact same label text not be used on multiple sectioning elements (or heading elements). This makes each section more recognizable to screen reader users which helps them navigate the site more easily.

There are three ways to label a sectioning element. In the following examples, I refer to "transport" and "portability" as a way of explaining how easy it is to save the section into a component and use that component multiple times in multiple different contexts.

I also provide lists of positives and negatives in the examples as well. In these lists, I assume that you want the section label to be readable by screen readers but hidden from sighted users.

Method 1: Add an aria-label attribute

This is the quickest and easiest way to label a sectioning element.

<section aria-label="Label for this section"> <p>Content for this section</p> </section> #The aria-label translation issue

The main draw back of aria-label (at the time of writing) is that most browsers are unable to translate these values for users who speak a different language than you. The developers at Google recently fixed this bug in Chrome, however this is still a problem for every other browser.

If your website has a large international audience or you know that many of your users do not speak your language, you should probably avoid using this attribute until all browsers support the translation of this property. If you don’t have those sorts of users, it’s pretty safe to assume that the non-sighted users viewing your site are able to understand your language — well enough to be able to navigate your site, anyway.

If you need more convincing, let's say your site has very few international users. That means your users generally come from the same country as you. If they come from the same country then they are likely to speak the same language as you, so there is already a fairly small percentage of your users that don’t understand the native language of your site. Now take into account that aria-label only affects screen reader users. That is now only a fraction of an already small percentage of your users who will experience the issue. And now consider that Chrome (by far the most popular browser in the world) now supports translation of the aria-label attribute. The user has to also not be using an up to date version of Chrome as their browser for the translation issue to be a problem. If you factor all of that together, it is highly probable that you may not have any users who are both able to perceive the aria-label attributes and are incapable of comprehending what they say. This makes me feel like the bad multi-lingual support in aria-label isn’t really worth worrying that much about unless you have a large international audience or you have many users that you know do not speak your language.

#Positives
  • Super quick and easy to implement.
  • Doesn’t affect heading structure.
  • Makes components easy to transport.
  • Is invisible to sighted users.
#Negatives
  • Not translated into other languages in non-Chrome browsers (at time of writing).
  • Often not supported by page structure analysis tools.
  • Confusion can arise from not knowing what level other headings inside the section should be at.
Method 2: Add a <h#> element to it

By <h#> I mean <h1>, <h2>, <h3>,<h4>,<h5>, or <h6> depending on what makes sense. Adding a heading to a sectioning element is a quick way to label it.

#Heading placement

The heading can be placed either directly in the sectioning element, like this:

<section> <h1>Heading</h1> <p>content</p> </section>

...or placed inside the <header> element:

<section> <header> <h1>Heading</h1> <p>I'm a byline</p> </header> <p>Content</p> </section>

You can also place as many <div> wrapper elements between the sectioning element and the heading as you want.

<!-- This is perfectly fine --> <section> <div> <header> <div> <h1>Heading</h1> <p>I'm a byline</p> </div> </header> <p>Content</p> </div> </section> #Only one heading of the highest level per sectioning element

There should really only be one heading of the highest level in a sectioning element. The spec says that when there are multiple top level headings or headings of a higher level than the first, the browser is supposed to close the previous sectioning element and start a new one of the same type.

The first element of heading content in an element of sectioning content represents the heading for that explicit section. Subsequent headings of equal or higher rank start new implied subsections that are part of the previous section’s parent section. Subsequent headings of lower rank start new implied subsections that are part of the previous one. In both cases, the element represents the heading of the implied section.

HTML 5.3, Headings and Sections

In reality, the browser uses the first heading as the section label but these implied sections are never created. It just announces the heading as is when it encounters it. It’s not earth-shatteringly bad but it is somewhat confusing.

<!-- Avoid this: --> <section> <h2>Heading level two labeling a section</h2> <p>Content</p> <!-- Don't use same level or higher headings as the one labeling the section --> <h2>This is also a heading level two</h2> <p>Content</p> </section> <!-- Do this instead: --> <div> <section> <h2>Heading level two labeling a section</h2> <p>Content</p> </section> <section> <h2>Heading level two labeling a different section</h2> <p>Content</p> </section> </div> #The heading always comes first

If a sectioning element has a <h#> element, that top level heading should always be the very first piece of content inside that sectioning element. Failing to do so counts as an accessibility fail.

If you find yourself needing to place content before your heading (like an image, for example), you can use Flexbox to rearrange the visual order. This will allow it to look like the image comes before the heading but in the markup the heading comes before the image. There is a bug in IE that will sometimes cause text to not wrap in a flex-direction: column; element. You can work around this issue by applying a max-width to the flex-child element.

<!-- Don't do this --> <section> <img src="image.jpg" alt="Don't place content or images before the heading" /> <h2>Headings should always come first</h2> <p>Place regular content after the heading</p> </section> <!-- Do this instead --> <section class="example"> <h2>Headings should always come first</h2> <img src="image.jpg" alt="Don't place content or images before the heading" /> <p>Place regular content after the heading</p> </section> <style> .example { display: flex; flex-direction: column; } .example img { order: -1; } </style>

Note that rearranging the visual order to satisfy WCAG Guideline 1.3.2: Meaningful Sequence can conflict directly with WCAG Guideline 2.4.3: Focus Order. For example, if that image is a link to an article and the heading you are placing it above is also a link to the article, placing the heading first breaks the focus order. Placing the image first breaks the meaningful sequence.

In situations like this where these two guidelines conflict with one another, my opinion is that the 1.3.2: Meaningful Sequence guideline is the more important guideline to follow if you aren’t able to resolve the conflict in some way. Failing focus order leads to the user suffering a moment of discomfort as they are tabbing through the content and focus is sent to an unexpected location. Failing to follow a meaningful sequence leads to a confused user unsure of the relationship between different bits of content.

#Making visually hidden section labels out of headings

Headings are visible to sighted users by default. This makes them super useful if you want the heading to be visible. A lot of the time, we don’t want the label for our sectioning element to be visible though. In order to stop our sighted users from seeing the label, we need to use some CSS.

<style> .visually-hidden { position: absolute; opacity: 0; pointer-events: none; } </style> <section> <h1 class="visually-hidden">Heading</h1> <p>content</p> </section> #Headings are well-supported by structure analysis tools

Headings also have a huge advantage for developers in that any page structure analysis tool that you can find will have support for them. This makes heading structures easy to test and debug. The other two section labeling methods have very poor support in testing tools. Not even the official W3C Validator service supports the alternatives at the moment. I posted an issue to have this fixed — please consider helping to fix the issue if you are good at coding in Java.

#Positives
  • Quick to implement.
  • Reliably appears in page structure analysis tools making it easy to test and debug.
  • All browsers will translate the text into other languages.
  • No confusion over what level other headings inside the section should be.
#Negatives
  • Affects document heading structure.
  • Need to ensure that the heading is at the correct level before use.
  • Visible to the user by default.
  • Requires CSS to hide the heading from visual users.
  • Can make components less portable due to heading structure requirements.
Method 3: Use an aria-labelledby attribute

This is what it looks like to create a hidden section label using aria-labelledby.

<section aria-labelledby="unique-id"> <div hidden id="unique-id">Label for this section</div> <p>Content for this section</p> </section> #Labels can be hidden without CSS

Note that I used the hidden attribute in the example to hide the div rather than a visually-hidden CSS class. aria-labelledby is able to read out text that is normally hidden from screen reader users. This adds the bonus effect of preventing the text from being read out twice by the screen reader. Don’t use the aria-hidden attribute though. Screen readers will not find the label text. Well, NVDA couldn’t find the label text when I tested it. I’m not sure about other screen readers.

#Major portability issue

aria-labelledby is the most difficult to use out of all the section labeling methods. The main aspect that makes it difficult to use is that the aria-labelledby attribute works off IDs. Things always get more complicated whenever IDs are involved. This is due to web pages only being allowed to have a single instance of an ID on the page at any one time. This makes component portability difficult.

Due to this portability issue, I would really only recommend this option if you need to support a multi-lingual audience and don’t want to mess around with the heading structure.

#No need to place the label near the sectioning element

You don’t need to place the element with the label text inside or near the section element that it labels. The text for the label can be placed in a completely different location to the sectioning element. This is thanks to the ID linking the two elements together. I’m not necessarily saying that it is a good idea to do this, but it is a feature of aria-labelledby that you should be aware of.

<div hidden id="unique-id">Label for this section</div> <!-- 1,000 lines of other HTML --> <section aria-labelledby="unique-id"> <p>Content for this section</p> </section> #Turn non-heading elements into section labels

There is one other key reason you may want to use aria-labelledby. If you have a visible non-heading element on the page that you want to use as the label for a section, aria-labelledby is perfect for this. A <legend> element inside a <fieldset> is a common use case for this. This doesn’t mean that you have to wrap fieldsets in sectioning elements. I’m just pointing it out in case you spot a need for it.

<section aria-labelledby="section_label"> <fieldset> <legend id="section_label"> I am both the fieldset legend and the section label </legend> <!-- Form fields go here --> </fieldset> </section> #Positives
  • All browsers will translate the text into other languages.
  • Can assign a non-heading element as the section label.
  • Text for the label does not need to be placed near the section it is labeling.
#Negatives
  • Requires the use of IDs to work.
  • Difficult to transport.
  • It can potentially be difficult to track down where the text for the label is stored in your source code.
  • Text is visible by default unless a hidden attribute is used.
  • Text might get read out twice by some screen readers if the text is not hidden.
  • Confusion can arise from not knowing what level other headings inside the section should be at.
Only use one method at a time

Don’t use a <h#>, an aria-label and/or an aria-labelledby attribute at the same time on the same sectioning element. Only every use one labeling method at a time for each sectioning element. Using multiple methods is super confusing and leads to the label being overwritten. It’s a bit like declaring the same property twice in CSS. I wasn’t sure how a screen reader would actually handle this so I created the most ridiculous <section> ever and ran it through NVDA.

<!-- Don't do this --> <section aria-label="Is this the section label?" aria-labelledby="is_this_the_label"> <h1>Or is this the section label?</h1> <p id="is_this_the_label">Only ever use one at a time.</p> </section>

This is the order of priority that NVDA gave to the various labeling methods from strongest to weakest:

  1. aria-labelledby
  2. aria-label
  3. <h#>
Adding section labels to our example layout

For a long time, I used headings as the only means of labeling sections. The poor multi-lingual support provided by aria-label scared me; and aria-labelledby was far too cumbersome to be my primary labeling method. We run into a bit of an issue though if we use only headings to label sections. I’ll show you what I mean.

<style> .visually-hidden { position: absolute; opacity: 0; pointer-events: none; } </style> <body> <header> <a href="/" title="Go to home page"> <img src="logo.png" alt="Site logo"> </a> <nav> <h2 class="visually-hidden">Primary</h2> <ul> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> </ul> </nav> <form role="search" aria-label="site"> <label> <span>Search</span> <input type="search"/> </label> <button type="submit">Submit</button> </form> </header> <nav> <h2 class="visually-hidden">Secondary</h2> <ul> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> </ul> </nav> <main> <article> <h1>Main article heading</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p> <h2>Article secondary heading</h2> <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p> <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p> </article> </main> <aside> <h2 class="visually-hidden">Sidebar</h2> <section> <h3>Share</h3> <ul> <li><a href="#">Facebook</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Email</a></li> </ul> </section> <section> <h3>Recommended</h3> <ul> <li> <article> <h4><a href="#">Related article</a></h4> <p>Article description</p> </article> </li> <li> <article> <h4><a href="#">Related article</a></h4> <p>Article description</p> </article> </li> </ul> </section> </aside> <footer> <ul> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> </ul> </footer> </body>

If we look at our heading structure now, it will look like this (italics = visually hidden; bold = visible):

li.no-list-dot::before { display: none; }
    • <h2> Primary [nav]
    • <h2> Secondary [nav]
  • <h1> Main article heading
    • <h2> Article secondary heading
    • <h2> Sidebar
      • <h3> Share
      • <h3> Recommended
        • <h4> Related article
        • <h4> Related article

Notice that our <h1> heading isn’t at the top of the list? It really doesn’t feel right having two <h2> headings above the <h1> heading.

This form of heading structure is actually allowed by the W3C so it doesn’t count as an accessibility fail. I still think that this is a pretty bad UX for screen reader users though. It is not a logical progression from <h1> to <h2>. It makes the most sense if the first heading you encounter on the page is a <h1> then progress into <h2> then <h3> and so on.

Making Heading 1 be the first heading

For a very long time, I thought the absolute best way to handle this conundrum was to make the <h1> visually hidden and have it be the very first piece of content on the page. The thing that everyone thinks is the <h1> actually becomes a <h2>.

This is what that sort of structure looks like in practice:

<style> .visually-hidden { position: absolute; opacity: 0; pointer-events: none; } </style> <!-- Don't do this --> <body> <header> <h1 class="visually-hidden">Main article heading</h1> <a href="/" title="Go to home page"> <img src="logo.png" alt="Site logo"> </a> <nav> <h2 class="visually-hidden">Primary</h2> <ul> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> </ul> </nav> <form role="search" aria-label="site"> <label> <span>Search</span> <input type="search"/> </label> <button type="submit">Submit</button> </form> </header> <nav> <h2 class="visually-hidden">Secondary</h2> <ul> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> </ul> </nav> <main> <article> <h2><span class="visually-hidden">Body:</span> Main article heading</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p> <h3>Article secondary heading</h3> <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p> <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p> </article> </main> <aside> <h2 class="visually-hidden">Sidebar</h2> <section> <h3>Share</h3> <ul> <li><a href="#">Facebook</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Email</a></li> </ul> </section> <section> <h3>Recommended</h3> <ul> <li> <article> <h4><a href="#">Related article</a></h4> <p>Article description</p> </article> </li> <li> <article> <h4><a href="#">Related article</a></h4> <p>Article description</p> </article> </li> </ul> </section> </aside> <footer> <ul> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> </ul> </footer> </body>

Now we have a document outline that looks like this (italics = visually hidden; bold = visible):

  • <h1> Main article heading
    • <h2> Primary [nav]
    • <h2> Secondary [nav]
    • <h2> Body: Main article heading
      • <h3> Article secondary heading
    • <h2> Sidebar
      • <h3> Share
      • <h3> Recommended
        • <h4> Related article
        • <h4> Related article

This mostly feels right. The <h1> is at the top and it all flows down perfectly with the <h2> elements representing major page sections and the <h3> elements representing sub sections. The main awkward bit is that the actual <h1> and the thing that everyone thinks is a <h1> are essentially duplicates of one another.

It wasn’t until I wrote up the first version of this article, had it nearly published, then had it thrown out the window, that I started to think differently. I talked with two accessibility consultants about the issue. They both agreed that, though this is a clever technical solution to the problem, it detracts from the experience of the very people that it is trying to help.

The issue is that when every other website in the world places the <h1> heading at the top of the main content area, that is what screen reader users come to expect. When your site is the special snowflake that does things differently, it confuses screen reader users and it takes them some time to figure out how your heading structure is supposed to work.

So, with that in mind, I’ve settled on a new method for handling the labeling of sectioning elements. Basically, any time I would have used a visually hidden heading, I would use an aria-label attribute now instead. If the site has a large non-native speaking audience, I would use aria-labelledby instead of aria-label.

Concerns with the simplified outline algorithm spec

If the simplified outline algorithm is approved in its current state, we will actually need to start structuring our sites like the visually hidden <h1> example anyway (just replace the <h2>, <h3> and <h4> elements with <h1> elements).

The original spec aimed to create the outline through the labeling of sectioning elements. This new spec is clearly aimed at trying to create the outline purely through heading levels. The algorithm basically calculates the heading level based on the number of ancestor sectioning elements a heading has plus the heading’s base heading level value. It's a bit more nuanced than that in the spec, but that is the general idea of how it works in simple terms.

The simplified algorithm currently makes no mention of aria-label or aria-labelledby. This means that those attributes will not help contribute to the document outline that the simplified algorithm generates. With a lack of aria-label support, this would mean labeling a sectioning element with aria-label could easily lead to skipped heading levels deeper in the tree.

<!-- Simplified algorithm skipped heading levels issue --> <body> <main> <h1>Primary heading for the page</h1> <!-- interpreted as <h1> --> <p>This is some content</p> </main> <!-- sectioning elements increase heading levels --> <aside aria-label="Side bar"> <!-- aria-label does not contribute --> <section> <h1>Share</h1> <!-- interpreted as <h3> --> <ul> <!-- list of social media links --> </ul> </section> <section> <h1>Recommended articles:</h1> <!-- interpreted as <h3> --> <ul> <!-- list of recommended articles --> </ul> </section> </aside> </body>

The simplified spec also considers it invalid to:

It does, however, allow for there to be more than one level 1 heading at the root of the document, which I find very odd and bad for accessibility (though my concern about this seems to have been ignored).

I have voiced the issues I have with the spec and proposed possible solutions in the GitHub discussion.

For the moment, it is still best to use aria-label and/or aria-labelledby attributes instead of visually hidden headings to label sectioning elements. It isn’t worth diminishing the experience of our present day users for the sake of a spec that hasn’t even been finalized or accepted yet.

Using aria on the example layout sectioning elements Using aria-label

This is what the HTML structure looks like if we use aria-label attributes to label the sectioning elements:

<body> <header> <a href="/" title="Go to home page"> <img src="logo.png" alt="Site logo"> </a> <nav aria-label="Primary"> <ul> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> </ul> </nav> <form role="search" aria-label="site"> <label> <span>Search</span> <input type="search"/> </label> <button type="submit">Submit</button> </form> </header> <nav aria-label="Secondary"> <ul> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> </ul> </nav> <main> <article> <h1>Main article heading</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p> <h2>Article secondary heading</h2> <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p> <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p> </article> </main> <aside aria-label="Sidebar"> <section> <h2>Share</h2> <ul> <li><a href="#">Facebook</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Email</a></li> </ul> </section> <section> <h2>Recommended</h2> <ul> <li> <article> <h3><a href="#">Related article</a></h3> <p>Article description</p> </article> </li> <li> <article> <h3><a href="#">Related article</a></h3> <p>Article description</p> </article> </li> </ul> </section> </aside> <footer> <ul> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> </ul> </footer> </body>

Here is the layout in CodePen in case you want to have a play around with it (sorry mobile users, it's not mobile friendly):

See the Pen
Mock up page layout v2 (sections article)
by Daniel Tonon (@daniel-tonon)
on CodePen.

Using aria-labelledby

But let’s assume that you have a huge international audience that speaks all sorts of languages. In that case, it is better to use the aria-labelledby attribute. Here is what that would look like:

<body> <header> <a href="/" title="Go to home page"> <img src="logo.png" alt="Site logo"> </a> <nav aria-labelledby="primary-nav-label"> <div id="primary-nav-label" hidden>Primary</div> <ul> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> <li><a href="#">Primary nav</a></li> </ul> </nav> <form role="search" aria-labelledby="search-label"> <div id="search-label" hidden>Site</div> <label> <span>Search</span> <input type="search"/> </label> <button type="submit">Submit</button> </form> </header> <nav aria-labelledby="secondary-nav-label"> <div id="secondary-nav-label" hidden>Secondary</div> <ul> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> <li><a href="#">Secondary nav</a></li> </ul> </nav> <main> <article> <h1>Main article heading</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p> <h2>Article secondary heading</h2> <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p> <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p> </article> </main> <aside aria-labelledby="sidebar-label"> <div id="sidebar-label" hidden>Sidebar</div> <section> <h2>Share</h2> <ul> <li><a href="#">Facebook</a></li> <li><a href="#">Twitter</a></li> <li><a href="#">Email</a></li> </ul> </section> <section> <h2>Recommended</h2> <ul> <li> <article> <h3><a href="#">Related article</a></h3> <p>Article description</p> </article> </li> <li> <article> <h3><a href="#">Related article</a></h3> <p>Article description</p> </article> </li> </ul> </section> </aside> <footer> <ul> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> <li><a href="#">Footer link</a></li> </ul> </footer> </body> Results of using aria

The heading structure for the site at this point looks like this:

  • <h1> Main article heading
    • <h2> Article secondary heading
    • <h2> Share
    • <h2> Recommended
      • <h3> Related article
      • <h3> Related article

The document outline (assuming that the original outline algorithm is implemented) looks like this:

  • <body> Document
    • <nav> Primary
    • <nav> Secondary
    • <article> Main article heading
      • <section (implied)> Article secondary heading
    • <aside> Sidebar
      • <section> Share
      • <section> Recommended
        • <article> Related article
        • <article> Related article

You might be thinking that the document outline looks a bit bare. Shouldn’t things like the header and footer and search be announced in there as well? Keep in mind that this is just the explicit stuff. We get a lot of implicit information provided to the user for free by using correct HTML elements in a good structure. This is a simplified version of how a screen reader user might experience the site:

  • [Text used in the <title> element]
    • Banner landmark
      • Link, site logo [(on focus) "go to home page"]
      • "Primary" navigation landmark
        • [List of navigation links]
      • "Site" search landmark
    • "Secondary" navigation landmark
      • [List of navigation links]
    • Main landmark
      • "Main article heading" article landmark, heading level 1
        • [Content]
        • Heading level 2, "Article secondary heading"
          • [Content]
    • "Sidebar" complimentary landmark
      • "Share" region landmark, heading level 2
        • [List of share links]
      • "Recommended" region landmark, heading level 2
        • List with 2 items
          • Item, "Related article" article landmark, heading level 3
            • [Content]
          • Item, "Related article" article landmark, heading level 3
            • [Content]
    • Content info landmark
      • [List of footer links]

As you can see, the site structure becomes quite clear and understandable to screen reader users when you factor in all of the extra implicit information that you get from using a good HTML structure

So, even though no browser supports the document outline algorithm, it is still worth putting some effort into thinking about the outline. Screen readers still tell users what type of section something is, where sections start and (sometimes) end (depends on the screen reader), and what the section label is. This means that your efforts to make a good document structure do not go to waste.

This type of structure comes with multiple benefits:

  • The page is 100% compatible with the document outline algorithm, future proofing it in-case the algorithm is ever implemented in a real browser.
  • The heading structure is completely logical.
  • Screen reader users navigating via headings can quickly jump to important information.
  • Screen reader users navigating via landmarks have lots of useful landmarks to move about the page.
  • Screen reader users are able to quickly understand what each section contains without having to read any of the content inside of them.
  • Content is grouped into semantic sections, so screen reader users do not get confused when leaving one section and entering another.
  • Search engines are able to better understand what information each section holds, which could potentially improve SEO.
  • Sighted users can take advantage of native browser features like Reader Mode.
What happens when you need h7?

There is one more sticking point when it comes to labeling sectioning elements that I haven’t addressed yet. Let’s say you have somehow managed to use up all six native heading levels and are now stuck needing one more. What do you do?

You could use the aria-labelledby technique if it is just for the sake of labeling a section. Let’s say that you really want this heading to appear in the heading structure though, or maybe you just want to avoid using IDs as much as possible. Whatever the reason, you need an <h7> element but <h7> doesn’t exist.

This is when the aria-level attribute comes to the rescue. The aria-level attribute will define what the heading level should be for elements that have role="heading" applied to them. This is how the W3C recommend creating a <h7> element:

<div role="heading" aria-level="7">This is a valid heading level 7 element</div>

Not all screen readers support this syntax. I know that JAWS treats these like <h2> elements rather than <h7> elements. If you know of any screen readers that this doesn’t work in, please report the bug to the screen reader developer and also leave a comment down below.

When I need to reach for an <h7>, I’ll often use the implied role="heading" from an <h6> element instead. The aria-level attribute will override the implicit "6" level of the <h6> element. This isn’t exactly endorsed by the W3C though. It is cleaner and will allow the heading to still appear in document outline and heading structure testing tools (though they will typically appear as <h6> or <h2> level headings, not as <h7> level headings).

<h6 aria-level="7">This is also a valid heading level 7 element</h6>

By using aria-level, you now have access to an infinite number of heading levels!

Does your site have a good structure?

Now that you know how to do a proper HTML structure, are you able to apply what you have learned to your website?

I found a pretty good browser extension called "Headings Map" that is available for both Chrome and Firefox. This extension will allow you to easily see both a flat heading structure representation of your site (i.e. how all browsers currently read the heading structure) and what the document structure looks like in a browser that supports the document outline algorithm (i.e. how a theoretical future browser that supports the outline algorithm would present the site structure). The HTML5 Outline view needs to be enabled in the settings menu first. This is to prevent users from being fooled into thinking that they are able to use the outline algorithm in production sites.

Headings Map does not currently support the aria-label and aria-labelledby attributes on sectioning elements in the HTML5 outline tab. I have been talking with the developer and he is working on fixing this issue. If you know of a good document outline testing tool that already takes aria-label and aria-labelledby into account, please share a link to it in the comments.

Once you have a good document structure testing tool, check that both the heading structure and the document outline display a logical order with no missing headings or missing section labels anywhere.

Download and use a screen reader

The best way to test the implied semantics that you get from using correct HTML is to download an actual screen reader and try navigating your site with it. NVDA is one of the most used screen readers used by real screen reader users. It’s also free!

Be aware that the default settings for NVDA are optimized for usage by blind users. These default settings can drive sighted users insane. To enjoy your time using NVDA, perform the following steps (steps are based on a Windows set up, I don't have a Mac):

  1. Download NVDA and install it
  2. Create a shortcut to NVDA in your task bar (You will be opening and closing it regularly while testing)
  3. Open NVDA from the task bar
  4. Find NVDA in your system tray
  5. Right click the tray icon > "preferences" > "settings"
  6. Select "mouse" in the left panel
  7. Deselect "Enable mouse tracking" (You can now move your mouse without NVDA screaming at you)
  8. Press "OK"
  9. Right click the tray icon > "Tools" > "Speech Viewer" (You can now see a log of everything NVDA says, don't rely purely on this when testing though)
  10. In the Speech Viewer, check the "Show Speech Viewer on Startup" checkbox (It will open the Speech Viewer when you open NVDA)
  11. Familiarize yourself with some of the keyboard controls
  12. To close NVDA, Right click the tray icon > "Exit" > "OK"

NVDA currently doesn't support <article> and <section> elements. There is an issue on GitHub for supporting <article> elements. When I began writing this article <section> elements were already supported. Support for <section> seems to have dropped for some reason. This means NVDA should be fixed. It doesn't mean you should stop using the correct semantics in your HTML.

Build your website with the document outline in mind then test the semantics with Headings Map and NVDA (or another screen reader). If you do, you will make your screen reader users very happy. You might even make the search engines happier too. &#x1f60a;

Special thanks to Kevin Galvin (a principal consultant at me 2 accessibility) for advice around the usability issues of using a visually hidden <h1> element at the top of the page and suggesting aria-label as an alternative to using visually hidden headings.

The post How to Section Your HTML appeared first on CSS-Tricks.

If you can build a site with WordPress.com, you should build your site on WordPress.com.

Css Tricks - Tue, 06/18/2019 - 4:19am

That’s what I like to tell people. I’ve seen too many websites die off, often damaging the company along the way because the technical debt of hosting and maintaining the website is too much in the long term. For a few examples, there is the domain name itself to handle and the tricky DNS settings to go along with it. There is choosing and setting up web hosting, which often requires more long-term maintenance than many folks would like. There are SSL certificates that need to be handled and renewed. You’d better make sure security and backups and handled well, lest you risk the entire site.

Lots of stuff to think about!

Building and working on a website is hard enough without all this stress. These things are even hard enough work for seasoned web people, and often just too much entirely for people, projects, and companies that just want a dang website.

You know what? Do it on WordPress.com and worry about nothing. Just build your website and know that a great company has got your back on everything else.

To be clear, I’ve been working on websites for decades. I know a lot about what it takes to run them and what can break them. To anyone that wants to learn those things too, that’s great. I would never try to that away from anybody. And there are plenty of projects out there that need to do things that WordPress.com can’t do. But there are also a lot more projects out there suffering from forgotten web chores and abandoned responsibilities that would be and could be happily chugging along on WordPress.com.

Signing up for a WordPress.com site is not just easy, but even includes a free tier. It's pretty incredible how quick it is to get a site online. And, if you're at all familiar with publishing content on WordPress, then you know how simple it is to start cranking out content — and if you're new to WordPress, well, you're in for a treat because the editing experience is just plain delightful, especially with the new Gutenberg interface.

So, yes, regardless your skill level, type or business, team, or whatever, WordPress.com is an excellent resource and is the right call. Does it fit all use cases? No, but nothing does. I like the idea of choosing the right tool for the job and WordPress.com can certainly be the right choice for a good number of projects.

Oh and hey, as chance has it, the awesome WordPress Jetpack plugin happens to be having a 20% promotion. That's pretty awesome. If you've been following us for some time, then you know that we love Jetpack and use it right here on CSS-Tricks — from comment moderation to image optimization to social integrations and many things in between. Use coupon code JPSAVE20 at checkout.

The post If you can build a site with WordPress.com, you should build your site on WordPress.com. appeared first on CSS-Tricks.

Managing State in React using Unstated-Next

Css Tricks - Mon, 06/17/2019 - 4:29am

In a previous post, we saw how to manage state using Unstated. As you might recall, Unstated uses React’s built-in setState to allow you create components that can consume state by subscribing to a provider — like the React’s Context API.

Well, we’re going to build off that last post by looking at Unstated Next, a library that author Jamie Kyle identifies as the “spiritual successor" to his Unstated project. Unstated Next provides both React Hooks and the Context API for managing state. Unstated was a minimal abstraction to the idea of React Hooks before they were a fully-fledged thing. But now that Hooks in React are so good, that abstraction is unnecessary and Unstated Next simply incorporates them while providing an API to share state and logic with the Hooks.

We’re going to specifically look at how to manage state in both single and multiple components using Unstated Next. It might be helpful to check out the previous post on Unstated prior to moving ahead, but it’s not totally necessary.

Example: A minimal form component

To start off, we’ll create a tiny React application for a form that merely contains a text input for a person’s name and a button to submit it. When the button is clicked, we’ll display the name as a paragraph element above the form. The source code for this example is available on GitHub.

This is going to be a Bootstrap React application which we can spin up by using Create React App. Let’s install that and then change directories into the project folder.

npx create-react-app unstated-next-form cd unstated-next-form>

We need to add Unstated Next as a dependency:

## yarn yarn add unstated-next ## npm npm install --save unstated-next

We’ll be making use of React Hooks and createContainer from Unstated Next, so let’s import those into the App component:

// src/App.js import React, { useState } from 'react'; import { createContainer } from "unstated-next";

Next, we will create a custom hook. We’ll have our state in it, which we can create using useState:

// src/App.js // ...same as before const useForm = () => { const [input, setValue] = useState(""); const [name, setName] = useState("Barney Stinson"); const handleInput = event => { setValue(event.target.value); }; const updateName = event => { event.preventDefault(); setName(input); setValue(""); }; return { input, name, handleInput, updateName, }; };

We have two states defined here. input will be used for keeping track of values entered into the text input and it will be updated using the handleInput method. name will be updated when the button is clicked, which will trigger the updateName method.

OK, now we can create a container by passing our custom hook as a parameter to the createContainer() method.

// src/App.js // ...same as before const FormContainer = createContainer(useForm);

This will create a container which we can use across our application. Yeah, you read that right, but let’s take one step at a time. We’re starting with this one component to see how it works with Unstated Next.

Now, let’s create a Form component that looks like this.

// src/App.js // ...same as before const Form = () => { const form = FormContainer.useContainer(); return ( <div> <p>Hello! {form.name}</p> <div> <input type="text" value={form.input} onChange={form.handleInput} /> <button onClick={form.updateName}>Save</button> </div> </div> ); };

We’re assigning the variable form to the value obtained from calling FormContainer.useContainer(). The value contains the states and methods defined in the custom hook we created above. With that, we can make use of the state and methods provided — but for that to happen, we have to wrap the Form component in a provider.

const App = () => ( <Form.Provider> <Form /> </Form.Provider> )

With what you have learned so far, try building a minimal to-do application using Unstated Next. If you get stuck, feel free to check this repository to see how I made mine.

Example: Sharing state across multiple components

OK, so you got a hint earlier that we can use our form container anywhere we’d like. One of the benefits of using Unstated Next is that it makes it possible to share state across multiple components. To see how this works, we’ll build a tiny app that uses the form features we made above and also makes it possible to create to-do tasks using the same state. The name of the user can be updated in the form component, and this update will also be reflected in the to-do component. Two birds of a feather!

There’s a repo for this example as well, so feel free to clone or download it as we plow ahead.

Let’s spin up a new project and install the necessary dependencies:

npx create-react-app unstated-next-app cd unstated-next-app yarn unstated-next shortid

The state for the application will live in a separate file. We want to have the states for the form and to-do components in the store, and the methods needed for updating them too. Create a store.js file inside the src directory and make it look like this;

// src/store.js import { useState } from "react"; import shortid from "shortid" import { createContainer } from 'unstated-next' export const useStore = () => { // Construct a list that contains two default tasks const list = [ { id: 1, title: 'Write code' }, { id: 2, title: 'Buy milk' } ] const [input, setValue] = useState(""); // Let's set a legen -- wait for it -- dary default name that updates on form submit const [name, setName] = useState("Barney Stinson"); const [todos, addTodo] = useState(list); const [item, setTodo] = useState(""); const handleInput = event => { setValue(event.target.value); }; const updateName = event => { event.preventDefault(); setName(input); setValue(""); }; const handleTodo = event => { setTodo(event.target.value); }; const handleSubmit = event => { event.preventDefault(); const value = { id: shortid.generate(), title: item } addTodo(todos.concat(value)); setTodo(""); }; return { input, name, handleInput, updateName, todos, item, handleTodo, handleSubmit }; } export const StoreContainer = createContainer(useStore)

We make use of useState() to create the states we need. The methods are defined and all of this happens inside the custom hook, useStore(). We create the StoreContainer and then pass useStore() as a parameter to createContainer(). With that, we can make use of the StoreContainer in the necessary components where want to make use of the state and methods we have defined.

Starting with the form section, create a file called form.js and it should look like what I have below;

// src/form.js import React from "react"; import { StoreContainer} from "./store"; const FormComponent = () => { const form = StoreContainer.useContainer(); return ( <div> <p>Hello! {form.name}</p> <div> <input type="text" value={form.input} onChange={form.handleInput} /> <button onClick={form.updateName}>Change Name</button> </div> </div> ); }; export default FormComponent;

We’re using StoreContainer to access the state and methods we need. We’ll do the same thing for the task component which you can create in a todo.js file.

// src/todo.js import React from "react"; import { StoreContainer } from "./store"; const TodoComponent = () => { const todo = StoreContainer.useContainer(); return ( <div> <p>Add Todos</p> <input type="text" value={todo.item} onChange={todo.handleTodo} /> <button onClick={todo.handleSubmit}>Add</button> <div> <p>Dear {todo.name}, here are your current tasks;</p> {todo.todos.map((item) => { return ( <ul key={item.id}> <li>{item.title}</li> </ul> ); })} </div> </div> ); }; export default TodoComponent;

You can see that todo.name can only be updated in the FormComponent. That’s because we need a way to provide the state in both components. That’s why we’re going to turn again to Provider and add one in the App component just like we did in the previous example.

import React from 'react'; import TodoComponent from "./todo"; import FormComponent from "./form"; import { StoreContainer } from "./store" function App() { return ( <div className="App"> <StoreContainer.Provider> <FormContainer /> <TodoContainer /> </StoreContainer.Provider> </div> ); } export default App;

There we go! By adding the provider, data can be taken from the form component, stored in the provider, and passed back to the task list. &#x1f4a5;

The post Managing State in React using Unstated-Next appeared first on CSS-Tricks.

Components, yo.

Css Tricks - Fri, 06/14/2019 - 3:57am

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.

Syndicate content
©2003 - Present Akamai Design & Development.