Using naming conventions such that you can learn them once and apply them everywhere
Unidirectional data flows. Make it easy to follow the app flow.
No magic numbers. I’d add they are even worse in CSS as it’s both the confusion they cause and how they are often tied to awkward or incorrect assumptions.
I interviewed Thierry Koblentz, creator of Atomic CSS, to understand the history and background that led to making of the popular CSS framework. Thierry, now retired, has vast experience writing CSS at large scale and has previously worked as a front-end engineer at Yahoo!.
Thierry is widely credited with bringing the concept of Atomic CSS to the mainstream, thanks to his now classic 2013 article on Smashing Magazine, “Challenging CSS Best Practices.” That article paved the way for many popular CSS libraries over the years. In this interview, Thierry returns to chronicle the history of Atomic CSS and reflect on its ongoing legacy.
Rolling back the years to the early 2000’s, how did you get into web development, especially writing CSS to make a living?
Thierry Koblentz: I taught myself HTML, CSS, and JavaScript as a hobby after moving to the U.S. in 1997.
At the time, I was using FrontPage and was relying heavily on Newsgroups for guidance. I quickly became a regular on Macromedia NewsGroups and on CSS-Discuss. Early on, I espoused the philosophy of the Web Standard Project and got really interested in Accessibility. For years, front-end was nothing more than a hobby for me (my real job was an antique dealer). I would create a website once in a while but I was mostly writing and publishing (many) articles, sharing techniques I’d learned or “discovered.”
This paid off in the form of a phone call from Yahoo! in 2007, asking if I could help fixing and building stylesheets for the Yahoo! Site Solutions (YSS) website builder template. The job description: no HTML, no JavaScript, just CSS! And a lot of it!
What was your day job at Yahoo! like?
TK: My role at Yahoo! changed a lot through the years.
My first job was to create stylesheets (à la CSS Zen Garden) for the YSS template. I then rewrote the markup and styles of the YSS website just before YSS was “shipped” to Bangalore (India) — where I was sent with my colleagues for “transfer of knowledge” purposes.
As a sidenote, it was the challenge of swapping stylesheets to create different designs for YSS that forced us to find a light (non-js) solution for resizing videos on the fly; and that’s how I came up with “Creating Intrinsic Ratios for Video.”
After YSS, I had the opportunity to only work on projects that started from scratch (rewrites or otherwise) and I got more and more involved with Yahoo! FE. I edited and created many internal docs (i.e. CSS Coding Standards); participated in the hiring process (like everybody else in my team); led code review sessions; ran CSS classes and workshops; spoke at FED London; helped other teams with HTML/CSS/accessibility; was involved in decisions regarding technology adoption (i.e. Bootstrap or not Bootstrap); created libraries; reviewed internal papers; wrote proposals; etc.
Another sidenote, during my eight years at Yahoo!, I may have written less than 100 lines of JavaScript. And if I didn’t quit or get fired from my job, it is thanks to Lingyan Zhu and Renato Iwashima; they helped me tirelessly when it came to setting up my environment or dealing with the command line (because, to this day, I am terrible at that).
What were the popular CSS writing practices prevalent at the time?
TK: In the early days, there were neither libraries nor published methodologies; it was the Wild West, everything went: “non-semantic” classes, IDs, CSS hacks, conditional comments, frames, CSS expressions, “JS sniffing,” designing primarily for Internet Explorer, etc. On my old website, I even had this comment:
<!--MSIE5 Mac needs this comment -->
Everything was fair game and everything was abused as we had a very limited set of tools with the demand to do a lot.
But things had changed dramatically by the time I joined Yahoo!. Devs from the U.K. were strong supporters of Web Standards and I credit them for greatly influencing how HTML and CSS were written at Yahoo!. Semantic markup was a reality and CSS was written following the Separation of Concern (SoC) principle to the “T” (which was overzealous for my liking at times though).
YUI had CSS components but did not have a CSS framework yet. There was an in-house CSS library (called Lego) but I never had to use it. Methodologies and libraries, like OOCSS, SMACSS, ECSS (shoutout to Ben), BEM, Bootstrap, Pure, and others would come shortly after.
What led to the idea of Atomic CSS?
TK: Before YSS was moved to India, my manager, Michael Montesano, asked if there was a way for the new team in Bangalore to avoid having to edit the stylesheet, and thus reducing the risks of breakage. I guess the YSS template experience (paying customers complaining about broken pages) made him pretty paranoid when it came to making any change to a stylesheet.
So I created a “utility-sheet” in the spirit of my ez-css library — a sheet meant to let developers achieve their styling without the need to edit or add rules in a stylesheet.
A couple of years later, Michael, then Director of Engineering, asked me if I could redesign Yahoo!’s Home Page using utility classes only, knowing that, once again, we wouldn’t be in charge of the website maintenance. We talked about prioritizing utility classes over semantic classes, something I don’t think existed at such a level at the time. It was a very bold move.
This large scale exercise quickly became a proof of concept that showed the many benefits that came with styling via markup. It checked so many boxes that it was decided that we’d use that “static” stylesheet (called Stencil) to redesign the Yahoo! My Home Page product.
What were the guiding principles while designing Atomic CSS (ACSS) and who were the people involved?
TK: Our Stencil library being static was a great tool to impose/enforce a design style — which we thought Yahoo! was about to adopt across all its properties. We quickly realized that this was not going to happen. Every Yahoo! design team had their own view of what was the perfect font size, the perfect margin, etc., and we were constantly receiving requests to add very specific styles to the library.
That situation was unmaintainable so we decided to come up with a tool that would let developers create their own styles on the fly, while respecting the Atomic nature of the authoring method. And that’s how Atomizer was born. We stopped worrying about adding styles — CSS declarations — and instead focused on creating a rich vocabulary to give developers a wide array of styling, like media queries, descendant selectors, and pseudo-classes, among other things.
With ACSS, developers were free to use whatever they wanted; hence teams were able to adopt different design styles and styles guides while using the exact same library. And there were some immediate benefits that were new to the way developers were used to writing styles. They no longer had to worry about breaking the page with their styling or worry about writing selectors to style their components.
ACSS was built first and foremost to address Yahoo!’s problems and to work in Yahoo!’s environment.
What misconceptions do people have about CSS when they don’t write CSS for large enterprises?
TK: When I joined Yahoo! in 2007, I quickly learned how enormous a codebase could be. There were teams working across many locations/timezones; a myriad of products; hundreds of shared components; third-party code; A/B testing strategies; scaling as a requirement; different script directions; localization and internationalization; various release cycles; complex deployment mechanisms; tons of metrics; legacies of all sorts; strict coding standards; build processes; politics; and more politics; etc.
Most of that was totally new to me and I had to learn if and how any of it could influence the way I was writing CSS. I started to revisit and challenge all my beliefs as many techniques or methods that were common practice to me seemed to be unfit, or at least counter-productive, for complex apps.
One “reality check” relates to style abstraction. We all have read articles saying that mapping a M-10 class to margin: 10px was not a good idea as it meant to edit both the HTML and CSS to change the styling. Unfortunately, this is what happens in large/complex projects:
Designer: I want a 15px gap
Developer: OK, that’s M-3x (5px increment)
Designer: Sure, whatever!
Developer: Done!
Designer: Actually, 15px is a bit too big, can you make it 12px?
Developer: No, we don’t have that, it’s either 10px or 15px.
Designer: Sorry, that doesn’t work for me. Can we change M-3x to be 12px?
Developer: Nope! We can’t do that because other teams expect M-3x to be 15px.
Designer: OK, try to figure a way because we want the margin to be 12px. 15px is too much and 10px is too little.
Developer: (F*ck this!)
To anticipate such a problem, one needs to understand the designer’s intent behind their request: is the style chosen because of its abstraction, e.g. color primary, or for its specific value, e.g. a margin of 15px in our M-3x case? If a style guide exists to enforce design principles, then classes like M-3x may be OK, but if design teams can request any style they want, then it is much safer to stay away from naming conventions that will lead to ambiguous styling. In my experience, anything ambiguous leads, sooner or later, to breakages.
Relying on the structure of a document or component for its styling — via combinators like > or + — sounds like a clean approach to authoring a stylesheet, but it is ignoring the fact that in a complex environment one cannot assume any specific markup, or construct, to be immutable.
You think z-index is complicated? Think again when you do not even own the scope of the stack your component lives in. That’s one of the most complex issues to address in a large project where teams are in charge of different parts of the page. I once wrote a proposal about this.
Qualifying selectors — like input.required vs. .input.required — may look good and semantic but it creates an unnecessary specificity level — like 0.1.1 vs. 0.2.0 — and prevents markup change; two things easy to avoid by making sure you do not qualify your selector.
Relying on the universal selector, *, for styling global scope? In a very large project, it could mean you are styling someone else’s component. Don’t make styling decisions for people unless you know their requirements.
I am sure you have read that IDs are bad and that specificity is evil but. in fact. high specificity is not as much of a problem as the number of specificity levels your rules create. It is much easier to style within an environment where only two or three levels exist — like 1.1.0, 0.1.0, 0.2.0 — rather than an environment where specificity is rather low but follows a “free for all” approach — like 0.1.0, 0.1.1, 0.2.0, 0.2.1, 0.2.2, etc. — which often comes as a defensive mechanism in large projects as a mean to “sandbox” styles.
Blindly following advice from the CSS community may lead to unpleasant surprises. Never jump on new techniques that have not yet been battle tested. Remember will-change? And always know what every style you use does or may trigger. For example, position can create a stacking context and a containing block, while overflow can create a block-formatting context.
In my experience, knowing CSS inside-out is not enough to write CSS efficiently for a large organization. During my tenure at Yahoo!, I often found myself in contradiction with people I used to be aligned with years before. The environment is brutal and one needs to be very pragmatic to avoid many pitfalls. Next time you look at the source code of a large project and see something that makes no sense to you, remember this tweet from Nicholas Zakas:
Instead of assuming that people are dumb, ignorant, and making mistakes, assume they are smart, doing their best, and that you lack context.
How was Yahoo!’s transition to Atomic CSS received internally?
TK: ACSS was well accepted by our My Home Page team, but it didn’t go well outside of that. Our first interaction was with the Sports team based in Santa Monica. Steve and I were in a conference call trying to convince the developers that not following the Separation of Concern’ principle was the way to go and that it would not create chaos.
We pointed them to a piece that Nicolas Gallagher had recently written, thinking that an article from an “outsider” would help, but nope! Things didn’t go well and there was a lot of friction. The main issue was the fact that the library was made of utility classes, but its syntax did not help to ease the conversation.
I recall also meeting with the Mail team who didn’t push back on the idea of Atomic CSS, but wanted to come up with their own JavaScript approach to use “plain” CSS declarations — as they could not stand the ACSS syntax. In any case, the data in favor of the library (~36% less CSSandHTML) was speaking for itself, so ACSS was eventually adopted. And today, seven-plus years later, Yahoo! Home Page, Yahoo! Sports, Yahoo! News, Yahoo! Finance, and other Yahoo! Products are all still using ACSS.
To better understand how an approach like ACSS can benefit projects where component reusability is paramount, copy the markup of a component from Yahoo! Finance and paste it inside Yahoo! News. That component should look like it belongs to the page. This is because ACSS makes these components page agnostic.
How did the idea of using parentheses for class names manifest? Was the syntax inspired from how functions are written?
TK: We had identified — through many iterations — two sets of “candidates” to be used as delimiters for property values: parentheses, (), and brackets, [].
Renato remembers that we picked parentheses over brackets because of familiarity with functions in JavaScript, even if it came at the cost of an extra Shift keystroke. The ACSS syntax was designed to:
facilitate the automatic generation of rules, via Atomizer
allow developers to create any arbitrary or complex styles they want
Developers build their classes following the above construct. The core syntax is based on Emmet, a popular toolkit. We adopted the Emmet approach to reduce idiosyncrasies as core classes are explicit property/value pairs rather than arbitrary strings.
We also created a dozen of helper classes. Those apply multiple style declarations and are either shortcuts, like hiding content from sighted users, or hacks, like using .Cf for clearfix. And we gave developers even more latitude through the use of a config file in which they can create variables — like .PrimaryColor — breakpoints, and much more.
People who’ve never worked with ACSS will tell you that the syntax is too weird (at best), but people familiar with it will tell you it’s clever in many ways.
Talk about how your “Challenging CSS Best Practices” article for Smashing Magazine came to fruition?
TK: I had written many articles in various online publications before, so it was natural for me to write an article about this “challenging” approach.
Yahoo! was sponsoring a front-end conference in October 2013 where Renato had a talk scheduled to present our solution, and I was trying to get the article published before that. I chose to not publish it on Yahoo! Developer Network because the website did not offer a comment section. A List Apart could not publish it in time, but Smashing Magazine accelerated its review process to be able to publish the piece before the end of October.
My choice of going with a publisher who had a comment section paid off as the article received 200-plus comments which turned out to be very time consuming — and frustrating — for me who had to respond to them.
Does it feel strange that the article still carries the disclaimer about the techniques discussed, even though it is widely popular in the industry now?
TK: When the article was published, I told Vitaly [Friedman, Smashing Magazine co-founder] that that note sounded like some type of a disclaimer to me; that it would sway people in their reading of the article. But I didn’t really push back as I understood where Vitaly was coming from. I do find it amusing that note is still there now this methodology has become mainstream.
Given that hindsight is 20/20, is there anything that you want to change about Atomic CSS?
TK: There is always room for improvement, even more so when you’ve pioneered the solution. You can’t look at what others have done to learn from their mistakes or shortcomings. You don’t have material to improve upon. So, it’d be pretentious for us to think we nailed it on our first try.
On the Atomic CSS side, we had a lot of experience for having developed and used a “static” stylesheet on a large project for more than a year. But on the dynamic side — the tooling side — it’s not like we could find much inspiration out there. Remember that it took six years for other libraries to follow suit.
In French, we say: essuyer les plâtres.
One mistake we made was to use “Atomic CSS” as the title for acss.io, because as John Polacek pointed out, it created some confusion. We’ve changed that title since then.
The only regret I have is how the community has treated Atomic CSS/ACSS through the years, which recently lead to a weird exchange, where somebody explained to me what “Atomic CSS” means:
The Atomic CSS library [ACSS] uses the name but I think this is misleading, because the feature you’re talking about is the dynamic style generation. “Atomic CSS” as a generic term designates small selectors as atoms, but they’re static.
Talk about being erased. 😉
A big thanks to Thierry for participating in this interview and allowing us to publish it for the community.
Here’s a super classy demo from Michelle Barker over on Codrops that shows how to build a scrollable and draggable timeline with GSAP. It’s an interesting challenge to have two different interactions (vertical scrolling and horizontal dragging) be tied together and react to each other. I love seeing it all done with nice semantic markup, code that’s easy to follow, clear abstractions, and accessibility considered all the way through.
The ability to identify users is vital for maintaining the security of any applications. Equally important is the code that’s written to manage user identities, particularly when it comes to avoiding loopholes for unauthorized access to data held by an application. Writing authentication code without a framework or libraries available can take a ton of time to do right — not to mention the ongoing maintainance of that custom code.
This is where Firebase comes to the rescue. Its ready-to-use and intuitive methods make setting up effective user identity management on a site happen in no time. This tutorial will work us through on how to do that: implementing user registration, verification, and authentication.
Firebase v9 SDK introduces a new modular API surface, resulting in a change to several of its services, one of which is Firebase Authentication. This tutorial is current to the changes in v9.
To follow along with this tutorial, you should be familiar with React, React hooks, and Firebase version 8. You should also have a Google account and Node installed on your machine.
Before we start using Firebase for our registration and authentication requirements, we have to first set up our Firebase project and also the authentication method we’re using.
To add a project, make sure you are logged into your Google account, then navigate to the Firebase console and click on Add project. From there, give the project a name (I’m using “Firebase-user-reg-auth”) and we should be all set to continue.
You may be prompted to enable Google Analytics at some point. There’s no need for it for this tutorial, so feel free to skip that step.
Firebase has various authentication methods for both mobile and web, but before we start using any of them, we have to first enable it on the Firebase Authentication page. From the sidebar menu, click on the Authentication icon, then, on the next page, click on Get started.
We are going to use Email/Password authentication. Click on it and we will be prompted with a screen to enable it, which is exactly what we want to do.
Cloning and setting up the starter repo
I have already created a simple template we can use for this tutorial so that we can focus specifically on learning how to implement the functionalities. So what we need to do now is clone the GitHub repo.
Fire up your terminal. Here’s what we can run from the command line:
git clone -b starter https://github.com/Tammibriggs/Firebase_user_auth.git
cd Firebase_user_auth
npm install
I have also included Firebase version 9 in the dependency object of the package.json file. So, by running the npm install command, Firebase v9 — along with all other dependencies — will be installed.
With done that, let’s start the app with npm start!
Integrating Firebase into our React app
To integrate Firebase, we need to first get the web configuration object and then use it to initialize Firebase in our React app. Go over to the Firebase project page and we will see a set of options as icons like this:
Click on the web () icon to configure our Firebase project for the web, and we will see a page like this:
Enter firebase-user-auth as the name of the web app. After that, click on the Register app button, which takes us to the next step where our firebaseConfig object is provided.
Copy the config to the clipboard as we will need it later on to initialize Firebase. Then click on the Continue to console button to complete the process.
Now, let’s initialize Firebase and Firebase Authentication so that we can start using them in our app. In the src directory of our React app, create a firebase.js file and add the following imports:
// src/firebase.js
import { initializeApp } from 'firebase/app'
import {getAuth} from 'firebase/auth'
Now, paste the config we copied earlier after the imports and add the following lines of code to initialize Firebase and Firebase Authentication.
Next up, we’re going to cover how to use the ready-to-use functions provided by Firebase to add registration, email verification, and login functionality to the template we cloned.
Creating User Registration functionality
In Firebase version 9, we can build functionality for user registration with the createUserWithEmailAndPassword function. This function takes three arguments:
auth instance/service
email
password
Services are always passed as the first arguments in version 9. In our case, it’s the auth service.
To create this functionality, we will be working with the Register.js file in the src directory of our cloned template. What I did in this file is create three form fields — email, password, and confirm password — and input is controlled by the state. Now, let’s get to business.
Let’s start by adding a function that validates the password and confirm password inputs, checking if they are not empty and are the same: Add the following lines of code after the states in the Register component:
// src/Register.js
// ...
const validatePassword = () => {
let isValid = true
if (password !== '' && confirmPassword !== ''){
if (password !== confirmPassword) {
isValid = false
setError('Passwords does not match')
}
}
return isValid
}
// ...
In the above function, we return an isValid variable which can return either true or false based on the validity of the passwords. Later on, we will use the value of this variable to create a condition where the Firebase function responsible for registering users will only be invoked if isValid is true.
To create the registration functionality, let’s start by making the necessary imports to the Register.js file:
// src/Register.js
import {auth} from './firebase'
import {createUserWithEmailAndPassword} from 'firebase/auth'
Now, add the following lines of code after the validatePassword password function:
// src/Register.js
// ...
const register = e => {
e.preventDefault()
setError('')
if(validatePassword()) {
// Create a new user with email and password using firebase
createUserWithEmailAndPassword(auth, email, password)
.then((res) => {
console.log(res.user)
})
.catch(err => setError(err.message))
}
setEmail('')
setPassword('')
setConfirmPassword('')
}
// ...
In the above function, we set a condition to call the createUserWithEmailAndPassword function only when the value returning from validatePassword is true.
For this to start working, let’s call the register function when the form is submitted. We can do this by adding an onSubmit event to the form. Modify the opening tag of the registration_form to look like this:
With this, we can now register a new user on our site. To test this by going over to http://localhost:3000/register in the browser, filling in the form, then clicking on the Register button.
After clicking the Register button, if we open the browser’s console we will see details of the newly registered user.
Managing User State with React Context API
Context API is a way to share data with components at any level of the React component tree without having to pass it down as props. Since a user might be required by a different component in the tree, using the Context API is great for managing the user state.
Before we start using the Context API, there are a few things we need to set up:
Create a context object using the createContext() method
Pass the components we want to share the user state with as children of Context.Provider
Pass the value we want the children/consuming component to access as props to Context.Provider
Let’s get to it. In the src directory, create an AuthContext.js file and add the following lines of code to it:
// src/AuthContext.js
import React, {useContext} from 'react'
const AuthContext = React.createContext()
export function AuthProvider({children, value}) {
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
)
}
export function useAuthValue(){
return useContext(AuthContext)
}
In the above code, we created a context called AuthContext along with that we also created two other functions that will allow us to easily use the Context API which is AuthProvider and useAuthValue.
The AuthProvider function allows us to share the value of the user’s state to all the children of AuthContext.Provider while useAuthValue allows us to easily access the value passed to AuthContext.Provider.
Now, to provide the children and value props to AuthProvider, modify the App.js file to look something like this:
Here, we’re wrapping AuthProvider around the components rendered by App. This way, the currentUser value supplied to AuthProvider will be available for use by all the components in our app except the App component.
That’s it as far as setting up the Context API! To use it, we have to import the useAuthValue function and invoke it in any of the child components of AuthProvider, like Login. The code looks something like this:
import { useAuthValue } from "./AuthContext"
function childOfAuthProvider(){
const {currentUser} = useAuthValue()
console.log(currentUser)
return ...
}
Right now, currentUser will always be null because we are not setting its value to anything. To set its value, we need to first get the current user from Firebase which can be done either by using the auth instance that was initialized in our firebase.js file (auth.currentUser), or the onAuthStateChanged function, which actually happens to be the recommended way to get the current user. That way, we ensure that the Auth object isn’t in an intermediate state — such as initialization — when we get the current user.
In the App.js file, add a useEffect import along with useState and also add the following imports:
// src/App.js
import {useState, useEffect} from 'react'
import {auth} from './firebase'
import {onAuthStateChanged} from 'firebase/auth'
Now add the following line of code after the currentUser state in the App component:
In the above code, we are getting the current user and setting it in the state when the component renders. Now when we register a user the currentUser state will be set with an object containing the user’s info.
Send a verification email to a registered user
Once a user is registered, we want them to verify their email address before being able to access the homepage of our site. We can use the sendEmailVerification function for this. It takes only one argument which is the object of the currently registered user. When invoked, Firebase sends an email to the registered user’s email address with a link where the user can verify their email.
Let’s head over to the Register.js file and modify the Link and createUserWithEmailAndPassword import to look like this:
// src/Register.js
import {useHistory, Link} from 'react-router-dom'
import {createUserWithEmailAndPassword, sendEmailVerification} from 'firebase/auth'
In the above code, we have also imported the useHistory hook. This will help us access and manipulate the browser’s history which, in short, means we can use it to switch between pages in our app. But before we can use it we need to call it, so let’s add the following line of code after the error state:
// src/Register.js
// ...
const history = useHistory()
// ...
Now, modify the .then method of the createUserWithEmailAndPassword function to look like this:
What’s happening here is that when a user registers a valid email address, they will be sent a verification email, then taken to the verify-email page.
There are several things we need to do on this page:
Display the user’s email after the part that says “A verification email has been sent to:”
Make the Resend Email button work
Create functionality for disabling the Resend Email button for 60 seconds after it is clicked
Take the user to their profile page once the email has been verified
We will start by displaying the registered user’s email. This calls for the use of the AuthContext we created earlier. In the VerifyEmail.js file, add the following import:
// src/VerifyEmail.js
import {useAuthValue} from './AuthContext'
Then, add the following code before the return statement in the VerifyEmail component:
In the above code, we are using optional chaining to get the user’s email so that when the email is null our code will throw no errors.
Now, when we refresh the verify-email page, we should see the email of the registered user.
Let’s move to the next thing which is making the Resend Email button work. First, let’s make the necessary imports. Add the following imports to the VerifyEmail.js file:
// src/VerifyEmail.js
import {useState} from 'react'
import {auth} from './firebase'
import {sendEmailVerification} from 'firebase/auth'
Now, let’s add a state that will be responsible for disabling and enabling the Resend Email button based on whether or not the verification email has been sent. This code goes after currentUser in the VerifyEmail component:
Now, if we go over to the verify-email page and click the button, another email will be sent to us. But there is a problem with how we created this functionality because if we try to click the button again in less than a minute, we get an error from Firebase saying we sent too many requests. This is because Firebase has a one minute interval before being able to send another email to the same address. That’s the net thing we need to address.
What we need to do is make the button stay disabled for 60 seconds (or more) after a verification email is sent. We can enhance the user experience a bit by displaying a countdown timer in Resend Email button to let the user know the button is only temporarily disabled.
In the VerifyEmail.js file, add a useEffect import:
import {useState, useEffect} from 'react'
Next, add the following after the buttonDisabled state:
In the above code, we have created a time state which will be used for the 60-second countdown and also a timeActive state which will be used to control when the count down will start.
Add the following lines of code after the states we just created:
In the above code, we created a useEffect hook that only runs when the timeActive or time state changes. In this hook, we are decreasing the previous value of the time state by one every second using the setInterval method, then we are stopping the decrementing of the time state when its value equals zero.
Since the useEffect hook is dependent on the timeActive and time state, one of these states has to change before the time count down can start. Changing the time state is not an option because the countdown has to start only when a verification email has been sent. So, instead, we need to change the timeActive state.
In the resendEmailVerification function, modify the .then method of sendEmailVerification to look like this:
Now, when an email is sent, the timeActive state will change to true and the count down will start. In the code above we need to change how we are disabling the button because, when the count down is active, we want the disabled button.
We will do that shortly, but right now, let’s make the countdown timer visible to the user. Modify the Resend Email button to look like this:
To keep the button in a disabled state while the countdown is active, let’s modify the disabled attribute of the button to look like this:
disabled={timeActive}
With this, the button will be disabled for a minute when a verification email is sent. Now we can go ahead and remove the buttonDisabled state from our code.
Although this functionality works, there is still one problem with how we implemented it: when a user registers and is taken to the verify-email page when they have not received an email yet, they may try to click the Resend Email button, and if they do that in less than a minute, Firebase will error out again because we’ve made too many requests.
To fix this, we need to make the Resend Email button disabled for 60 seconds after an email is sent to the newly registered user. This means we need a way to change the timeActive state within the Register component. We can also use the Context API for this. It will allow us to globally manipulate and access the timeActive state.
Let’s make a few modifications to our code to make things work properly. In the VerifyEmail component, cut the timeActive state and paste it into the App component after the currentUser state.
Now we can access timeActive and setTimeActive within the children of AuthProvider. To fix the error in our code, go to the VerifyEmail.js file and de-structure both timeActive and setTimeActive from useAuthProvider:
With this, a user will be able to send a verification email without getting any errors from Firebase.
The last thing to fix concerning user verification is to take the user to their profile page after they have verified their email. To do this, we will use a reload function in the currentUser object. It allows us to reload the user object coming from Firebase, that way we will know when something has changed.
First, let’s make the needed imports. In the VerifyEmail.js file, let’s add this:
// src/VerifyEmail.js
import {useHistory} from 'react-router-dom'
We are importing useHistory so that we can use to navigate the user to the profile page. Next, add the following line of code after the states:
// src/VerifyEmail.js
const history = useHistory()
And, finally, add the following lines of code after the history variable:
In the above code, we are running the reload function every one second until the user’s email has been verified, and, if it has, we are navigating the user to their profile page.
To test this, let’s verify our email by following the instructions in the email sent from Firebase. If all is good, we will be automatically taken to our profile page.
Right now the profile page is showing no user data and he Sign Out link does not work. That’s ur next task.
Working on the user profile page
Let’s start by displaying the Email and Email verified values. For this, we will make use of the currentUser state in AuthContext. What we need to do is import useAuthValue, de-structure currentUser from it, and then display the Email and Email verified value from the user object.
Here is what the Profile.js file should look like:
With this, the Email and Email verified value should now be displayed on our profile page.
To get the sign out functionality working, we will use the signOut function. It takes only one argument, which is the auth instance. So, in Profile.js. let’s add those imports.
// src/Profile.js
import { signOut } from 'firebase/auth'
import { auth } from './firebase'
Now, in the return statement, modify the that contains “Sign Out” so that is calls the signOut function when clicked:
Creating a Private Route for the Profile component
Right now, even with an unverified email address, a user can access the profile page. We don’t want that. Unverified users should be redirected to the login page when they try to access the profile. This is where private routes come in.
In the src directory, let’s create a new PrivateRoute.js file and add the following code to it:
This PrivateRoute is almost similar to using the Route. The difference is that we are using a render prop to redirect the user to the profile page if their email is unverified.
We want the profile page to be private, so well import PrivateRoute:
// src/App.js
import PrivateRoute from './PrivateRoute'
Then we can replace Route with PrivateRoute in the Profile component. The Profile route should now look like this:
Nice! We have made the profile page accessible only to users with verified emails.
Creating login functionality
Since only users with verified emails can access their profile page when logged in with the signInWithEmailAndPassword function, we also need to check if their email has been verified and, if it is unverified, the user should be redirected to the verify-email page where the sixty-second countdown should also start.
These are the imports we need to add to the Login.js file:
import {signInWithEmailAndPassword, sendEmailVerification} from 'firebase/auth'
import {auth} from './firebase'
import {useHistory} from 'react-router-dom'
import {useAuthValue} from './AuthContext'
Next, add the following line of code among the states in the Login component.
// src/Login.js
const {setTimeActive} = useAuthValue()
const history = useHistory()
Then add the following function after the history variable:
This logs in a user and then check if whether they are verified or not. If they are verified, we navigate them to their profile page. But if they are unverified, we send a verification email, then redirect them to the verify-email page.
All we need to do to make this work is call the login function when the form is submitted. So, let’s modify the opening tag of the login_form to this:
In this tutorial, we have learned how to use version 9 of the Firebase Authentication to build a fully functioning user registration and authentication service in React. Is it super easy? No, there are a few thing we need to juggle. But is it a heck of a lot easier than building our own service from scratch? You bet it is! And that’s what I hope you got from reading this.
With the ever-growing demand for data in the world around us, organizations are in a rat race of sorts to improve data accumulation methods and improve the overall efficiency of their data.
Data visualization is an integral part of the data revolution today and has helped many organizations come out on top as far as customer data and equipment data is concerned. Data visualization has popped up as an important tool recently, as it helps businesses grow and compete in the ever-changing world to improve their bottom line for further growth.
Data visualization has played a key role in helping organizations grow and become more competitive in the data-centric world of today. Stats from 2020 reveal that a staggering 67 percent of all small businesses were spending over $10k towards data analytics and other related measures. This percentage itself is an indication of the growing importance of data and how it matters in the world today.
Understanding Data Visualization
The growing traffic of data from multiple sources has created a problem of sorts for organizations. Companies with large customer bases may find it hard to keep track of all customers and demand metrics, especially since trends are regularly changing.
Generating data from customers is one thing and working on that data to churn out actionable insights is another. Companies with large customer bases find it hard to gather data in a simple format and get structured results from it.
Organizations and business managers looking to make sense out of their data have to come up with new visualization methods so that their data is easy to understand and accessible to all. To ensure that you utilize the full potential of your data, it is necessary that you group it and visualize it in the following ways:
Charts
Scatter plots
Histograms
Maps
Diagrams
Matrices
Dendrograms
Timelines
Treemapping
Tables
The terabytes of data you have currently accessible to you are just a bunch of jumbled numbers in their raw form. Unless you structure and visualize that data, you will not be able to make sense and decisions out of it. Visualizations make the process of structuring and understanding data easier and give users a simple way to generate results.
With the access of data from multiple sources, data visualization has also proved to be a technically tough nut to crack. Organizations can either head to third-party solutions or use the skills of in-house developers and harness the potential of Python for the job.
Languages like PHP and others have long been preferred for visualization techniques, but Python developers can use the potential of the language to increase efficiency and incorporate the true benefits of the programming language.
Let us study Python as a programming language today and look at the potential it hosts for data visualization and other related tasks.
Problems Associated with Python
Just like any other programming language, there are certain problems that you may face while visualizing data using Python. Python inherently lacks the powerful visualization frameworks that you may find in programming languages like PHP. Python does have the potential, but it falls short.
Python comes with Matplotlib, Seaborn, and Pyplot as data libraries, but they are either really heavy or have issues with the syntax.
Advantages of Python
Having looked at the problems associated with Python, we now look at the advantages which make Python recommended for data visualization.
The advantages mentioned below make the programming language a solid option for your data visualization techniques.
Open Source
Python is an open-source programming language, which allows developers to extend it based on the results they prefer. Developers working on Python are always creating new libraries, frameworks, and features, which add to the potential of the language. Python can be easily accessible to all and is free to use.
Simple to Learn
The learning curve for Python isn’t that complex, and your developers will be able to use it for data visualization in no time. Developers will be able to ease into the process and will have no problems whatsoever in integrating Python within the data visualization system of choice.
Connectivity
Perhaps one of the biggest upsides going in favor of Python is that it can connect to almost all database systems on the internet. Regardless of the system, you prefer for data collection, you can connect Python and use them both together.
Scalable for Growth
Scalability is another aspect where Python rises to the challenge and gives amazing results. Python has amazing scalability and can grow with the pace of your data requirements. If you have a business that generates a significant amount of data, python should be able to grow with the pace and match the data generation capabilities.
Major Python Libraries
Python comprises a number of libraries that can help in data visualization. While we did earlier mention that these libraries aren’t as fast as those of PHP, they can still handle the requirements of data visualization and produce exceptional results. Some of the top libraries include:
Bokeh: The Bokeh library can handle live streaming of data and can create web plots with an interactive design.
Geoplotlib: The geoplotlib can be used for plotting graphs that display geographical data pertaining to all users.
Gleam: Gleam gives you the ability to create actionable results and produce interactive applications entirely based on Python.
While Python isn’t considered to be the best option for data visualization, we recommend it because of the scalability and flexibility on offer. The open-source nature of the programming language allows developers to work on it and bring data to life through visualizations.
User Experience (UX) design and User Interface (UI) design are two terms people sometimes mistakenly use interchangeably. While aspects of each are interconnected, there are distinct differences between UI/UX design.
According to Internet Live Stats, there are over 1.9 billion websites, but not all are active at the same time. No matter how you slice it, there’s a lot of competition to grab and keep user attention. Good UX is just part of the equation. For a genuinely stellar site, you must also offer an excellent interface.
Learning the ins and outs of good UI and UX requires a bit of knowledge of how the two differ and what works. Although they weave in and out of the same design, they are different.
What Is the Biggest Difference Between Good UX and UI?
UI is the functionality of the design and what users see. How do they interact with various elements? UX is more the way things come together — both visual and interactive features — to create a feel for the user. You can certainly see why people confuse the two as they both apply to interacting with a website or app.
Top design firms often have team members specializing in each discipline. However, UX designers are also aware of UI, and UI designers are also mindful of UX. How can you ensure you’re offering excellent UI/UX design while covering the full spectrum of requirements for each?
Ensuring Effective UX Design
Good UX design increases conversion rates by 400% or more. The site visitor walks away feeling understood and not frustrated. What are some of the most important aspects of good UX design?
1. Create a Good Structure
What is the hierarchy of your site? What is the first thing the user sees when they pull it up? How do they navigate from one page to the next? A well-designed website classifies different aspects of the page, and new content naturally falls into the appropriate category as it grows.
When creating a structure for your site, think about how it might expand in the next five years. You want the hierarchy to work from day one, but you also want to think through significant shifts in the content you might see down the road.
Even your navigational hierarchy should accommodate new areas easily. Plan for the unexpected, so you know how to work it into the overall design when you must.
2. Choose Beautiful Aesthetics
You have a few seconds to make an excellent impression on your site visitors. Take the time to make sure your design functions and is visually appealing. Your color palette should work, images should be crisp and relevant, and typography should be readable and engaging.
Step back from your computer and look at your design from a distance. Does anything stand out that isn’t pleasing to the eye? Get feedback from visitors about what they like and dislike. Since the focus is on user experience, your best source of constructive criticism is from your target audience. Listen to their concerns and ideas.
3. Communicate With Site Visitors
Most experts agree that users want an element of interactivity on sites and apps. People want to know you hear them and get a response. Some ideas include adding a live chat option to your site or engaging in SMS customer support.
Put yourself in their shoes. A customer may visit your site for the first time, having never heard of your brand. They have no reason to trust you or that you’ll follow through on your promises. Potential leads may have a few questions before parting with their hard-earned dollars.
Adding various ways to communicate shows them you’ll be there should they have a problem. It’s much easier to trust a company when you know you can phone, engage in live chat or shoot off an email and get an almost immediate response.
4. Add Clear Direction
Excellent UX is intuitive. You should add calls to action (CTAs) and images pointing the user where they should go next. You can use graphics of arrows, people looking or pointing toward the next step, words, or CTA buttons.
Get feedback on how clear the directions are and tweak them as needed. The user should never have to stop and ponder what to do next. Everything on the page should guide them toward the ultimate goal.
5. Break Down Complex Data
Every industry has complicated data that is difficult for non-experts to understand. Part of good UX is breaking down complex information and sharing it in a simplified way.
One example might be the registration process. Instead of just showing text, a good UX designer would number the steps. Visualizations help add to understanding.
Embracing Effective UI Design
User Interface impacts UX and involves how the design works. The UI designer thinks through visitor expectations and then creates an interface that isn’t frustrating. UI works within the framework of a website to develop functional features. User experience isn’t the complete focus of UI, but it does tie into the planning phases. What are some elements of good UI design?
1. Set Standards
For a design to have good UI, it must perform as expected. Have you ever clicked on a button, and nothing happened? Determine how you want things to work and the minimum acceptable standards for your site.
For example, what happens when someone clicks on a link or button? How does the user know their action created the expected result? Consistency is crucial to how a site performs.
2. Choose the Right Colors
While UX designers look at the emotional impact of various colors, UI designers look at whether the shades match branding and how well the different ones contrast for readability and usability. UI/UX design often bridges a single designer’s work, so the employee ensures everything works as intended, both emotionally and functionally.
You may work with another designer to make the site aesthetically pleasing while also tapping into the emotions driving users. For example, some people love blue, so a blue button can have positive results.
UX and UI designers utilize split testing to see which users respond best to. Then, make adjustments as indicated by how site visitors respond.
3. Focus on Cognitive Matters
According to the Interaction Design Foundation, people can only retain around five things in their short-term memory. Designers should work with recognition instead, as users tend to rely on cues to find what they need.
UI designers may develop an intuitive navigation system and then use the same cues on every page, such as placement, color, and language. Users can then recognize the system without having to memorize it.
4. Prevent Errors
Your job is to ensure errors are kept to a minimum when designing a website or app. One of the most significant parts of a designer’s job is testing and retesting.
Think about all the potential problems a user might run into, such as broken links, images not showing, or incomplete actions. How can you keep those problems from occurring in the first place?
Error prevention is particularly vital when designing software as a service (SaaS) or apps. Users grow frustrated quickly and will find another solution rather than troubleshooting an issue. You’re much better off avoiding the error in the first place.
How Do UX and UI Work Together?
You’ve likely already figured out how closely UX and UI entwine to create a usable experience. The UX designer pays attention to function and interactivity, and the UI designer thinks through how the interface looks.
UX pays attention to the flow of the website and where users start, go next and end up. On the other end, UI figures out how the elements look to the viewer and where everything is placed.
The UX team may decide to add an extra button to the page. The UI team must determine where to place it, if any sizing needs must occur, and how it impacts usability on desktop and mobile devices.
Although each has a different function, user experience and user interface must work together to create a usable site the target audience responds to. You can’t have excellent UX without excellent UI, and vice versa. The best designers consider both and implement them to their fullest potential.
I have a coworker who is smart, capable, and technologically-literate. Like me, they work on the web full-time.
When they are sharing their screen in a meeting, I find myself disassociating fixating on the red update button in their copy of Chrome.
Clicking this button would start the process to update Chrome to the latest stable version.
I’ve asked some probing questions about how frequently they reboot, which would also force Chrome to update upon relaunch. That’s the point of an “evergreen” browser, right? It’s easy to make sure you’re always using the latest and greatest version.
It turns out they prefer to wait until they absolutely have to because of the disruption it would cause in their daily workflow. Their behavior makes sense. They are prioritizing the quality of their overall computing experience, rather than catering to the demands of one specific app.
Like me, my coworker also uses a top-of-the-line laptop to get things done. This means that the laptop can go for months without needing a reboot. Ironically, this might be a situation where a craptop is conditionally forced to have a faster browser upgrade path.
Evergreen browsers
Before the advent of evergreen browsers, you would need to go to the manufacturer’s website and manually download and install the update. Prior to that you had to use a CD or floppy disk.
By contrast, an evergreen browser is any browser that can automatically update itself. By this, I mean the browser will automatically pull down the code required to add new features and fix bugs once it has been released by the browser’s manufacturer. The update itself occurs with:
a prompt shown to the person using the browser that prompts an application restart,
a download that happens in the background and gets applied on application restart, or
on device restart.
The browsers themselves
Nearly all major browsers are evergreen. This includes Google Chrome, Microsoft Edge, and Mozilla Firefox.
Apple Safari is quasi-evergreen. By this I mean it automatically receives updates, but awkwardly requires them to be done when updating the macOS operating system with other system-wide updates.
If you haven’t been paying attention, the Safari team has been making a ton of improvements to their browser in the past few months—I’d love to see them continue with this trend by making the browser update path decoupled from existing macOS and iOS upgrade workflows.
Spending less time does not mean spending no time, however.
Delayed effects
Support from all evergreen browsers on caniuse.com does not necessarily mean support exists on the device a person is using—updates that have been “pushed” out don’t automatically get instantly applied.
Because of these two factors, I advocate for tempering your excitement with some restraint. It can be very tempting to rush and use the new and the shiny. Believe me, I’m not exempt from this urge—CSS is about to go from great to amazing, and the urge to use new features is very real.
Both CSS and JavaScript have the ability to conditionally serve up experiences for browsers that support new features while providing alternatives for those that don’t.
Instead of looking at the support table for something on caniuse.com and thinking, “I wish more browsers supported this feature so that I could use it!”, you can instead think “I’m going to use this feature today, but treat it as an experimental feature.”
You can use JavaScript to query whether or not a browser supports a certain feature. For example, the Navigator interface provides a mechanism for querying a user agent’s capabilities.
if (!(“geolocation” in navigator)) {
// Logic if a user's current geographic location isn't available
} else {
// Logic that is based on a user's current geographic location
}
In this example, I am inverting a request for support for a browser’s Geolocation interface. Although its syntax is initially a little confusing to parse, it helps emphasize a progressive enhancement approach. That is, assume geolocation functionality isn’t supported and be sure to prove a way to accommodate the person using this browser. This could have been any other feature, like letting a user type in an address or ZIP Code. With that use case covered, you can then confidently build an experience that utilizes a browser’s geolocation capabilities.
This thinking also extends to all other browser features and capabilities.
CSS
Like most other programming languages, CSS also lets us use if-like statements.
For example, the @supports at rule allows you to create a conditional statement that targets whether or not a browser supports something, and then apply logic to it. Browsers that honor the feature will utilize those styles, and browsers that don’t will ignore them. It is a concise, clever, adaptable solution.
.component {
/* Base appearance */
}
@supports (grid-template-columns: subgrid;) {
.component {
/* Styling and positioning enhancement tweaks if subgrid is supported */
}
}
For this example, this progressive enhancement approach ensures that a component’s content and functionality is preserved for every browser, but only creates fancy layouts for browsers capable of supporting them.
When can I remove this stuff?
Yes, this approach adds more code, and more code means more complexity and maintenance. But it’s very important code. You may even call it technical debt and you’d be correct. But technical debt can be a good thing, like an investment in the future.
You may want to remove that complexity when it’s no longer needed. Knowing the right time to do that in this age of evergreen browsers is difficult, but I have a couple of suggestions:
Patience is a virtue
In terms of waiting, I’d advise a conservative 6-ish months from release of a new feature before even beginning to think about investigating if you can remove feature detection. This accounts for:
Reboots
Update procrastinators
Update avoiders
Hardware refresh cycles
Corporate update policies,
etc.
I would also say that rough six month timeframe is in terms of a general, global web audience. This guesstimate changes if you cater to a specialized audience. The way to know who you actually serve? Analytics, yes, but also talking to people.
Maybe don’t
Remember: survivor bias is real. Is the brand new feature you’re using preventing someone from using your website or web app? I say this because some people:
are forced to use a device that is managed by a third party,
use “dead” evergreen browsers, devices that used to receive browser updates, but are no longer supported by their manufacturer.
There isn’t a single, specific device, browser, and person we cater to when creating a web experience. Websites and web apps need to adapt to a near-infinite combination of these circumstances to be effective. This adaptability is a large part of what makes the web such a successful medium.
Consider doing the hard work to make it easy and never remove feature queries and @supports statements. This creates a robust approach that can gracefully adapt to the past, as well as the future.
The future is uncertain
We’re long past the age of desktop computers. Browsers are showing up in more and more places: phones, tablets, watches, ebook readers, digital cameras, kiosks, televisions, home assistants, vending machines, photo frames, graphing calculators, ATMs, point of sale terminals, exercise equipment, video game consoles, billboards, refrigerators, virtual reality, and cars.
Who knows what devices browsers will be included with in the future, or what capabilities they’ll have? Future-proof (and, er, past-proof) yourself with an approach that accommodates it.
Paper documents were the original metaphor for the web. […]
The page you’re reading this on still mimics paper. We still call it a page or an HTML document. It follows the same typographic rules and conventions – black text on white backgrounds and a top-to-bottom / left-to-right heirarchical structure.
Over in the ShopTalk Discord, the idea of CSS custom properties named --ink and --paper came up the other day as abstractions for color and background-color and I kinda like it. There’s something more clear about the meanings of those terms to me.
But Maggie gets into some of the downsides of the paper-based metaphors, pointing out Ted Nelson’s critiques. This is interesting:
We treat the page as the smallest unit of linkable information, instead of the sentence or paragraph.
Will the main metaphor of the web as paper change in time? I’d say it’s highly likely. The interactivity and behavior we expect on the web today is a million miles different than we expected in the past and that’s going to keep happening. These updates accelerate the change. Perhaps someday the metaphors will have shifted to “alternate neighborhood,” “second brain,” or “dedicated assistant.”