Did you know that you can learn programming online from institutions like Harvard, MIT and Microsoft on edX.org? The nonprofit site offers 2000 online courses from 140 institutions worldwide. Courses are free to try.
If you want to become a front-end web developer, it can be difficult to figure out where to begin. Which frameworks, languages, and libraries should be your focus? The Microsoft Professional Program in Front-End Web Development is a curriculum that eliminates some of this confusion by introducing you to the fundamentals, teaching the most frequently used tools, and then offering a way for you to prove you have the skills through a final capstone project that can be showcased in your portfolio.
Here are some of the more popular courses Microsoft offers for front end web development:
In this 4 course program, learn the fundamentals of computer science in one of the field’s most popular programming languages, Python 3, including writing code, executing it, interpreting the results, and revising the code based on the outcomes. Rated as one of the most in-demand and beginner-friendly programming languages, a background in Python will give you a solid foundation to build your career. Short videos (2-3 minutes each) are rapidly interwoven with live programming problems and multiple-choice questions to give you constant feedback on your progress and understanding.
Did you know that smartphones, your car’s navigation system, robots, drones, trains, and almost all electronic devices have some C-code running under the hood? Along with the C programming language comes Linux, an essential operating system that powers almost all supercomputers and most of the servers worldwide, as well as all Android devices and most “Internet of Things” devices.
In this 7 course program, develop and debug code in the C programming language. Discover the foundations of computer programming and Linux, manipulate the command line, manage processes, files and memory, and compile C code with Linux.
Data science is one of the hottest fields in programming. Learn key data science essentials in this 9 course program, including R and machine learning, through real-world case studies to jumpstart your career as a data scientist. Also learn statistical concepts such as probability, inference, and modeling and how to apply them in practice. Gain experience with data visualization with ggplot2 and data wrangling with dplyr. Become familiar with essential tools for practicing data scientists such as Unix/Linux, git and GitHub, and RStudio. This is one of the most popular programs on edX.
Everyone has heard of blockchain, but most don’t understand how it can apply to their business. Learn exactly what a blockchain is, its impact and potential for change around the world, and analyze use cases in technology, business, and enterprise products and institutions in this fundamental course from the experts at the Linux Foundation.
If you are looking for something else, edX offers beginner to advanced programming courses in C++, C#, Java, Power BI, Artificial Intelligence, Machine Learning, Deep Learning, Cybersecurity, IoT, Cloud Computing, AWS, Azure, DevOps, and more. View more courses here.
We have a whole selection of ways to align things in CSS today, and it isn’t always an obvious decision which to use. However, knowing what is available means that you can always try a few tactics if you come across a particular alignment problem.
In this article, I will take a look at the different alignment methods. Instead of providing a comprehensive guide to each, I’ll explain a few of the sticking points people have and point to more complete references for the properties and values. As with much of CSS, you can go a long way by understanding the fundamental things about how the methods behave, and then need a place to go look up the finer details in terms of how you achieve the precise layout that you want.
Aligning Text And Inline Elements
When we have some text and other inline elements on a page, each line of content is treated as a line box. The property text-align will align that content on the page, for example, if you want your text centered, or justified. Sometimes, however, you may want to align things inside that line box against other things, for example, if you have an icon displayed alongside text, or text of different sizes.
In the example below, I have some text with a larger inline image. I am using vertical-align: middle on the image to align the text to the middle of the image.
Remember that the line-height property will change the size of the line-box and therefore can change your alignment. The following example uses a large line-height value of 150px, and I have aligned the image to top. The image is aligned to the top of the line box and not the top of the text, remove that line-height or make it less than the size of the image and the image and text will line up at the top of the text.
It turns out that line-height and indeed the size of text is pretty complicated, and I’m not going to head down that rabbit hole in this article. If you are trying to precisely align inline elements and want to really understand what is going on, I recommend reading “Deep Dive CSS: Font Metrics, line-height And vertical-align.”
When Can I Use The vertical-align Property?
The vertical-align property is useful if you are aligning any inline element. This includes elements with display: inline-block. The content of table cells can also be aligned with the vertical-align property.
The vertical-align property has no effect on flex or grid items, and therefore if used as part of a fallback strategy, will cease to apply the minute the parent element is turned into a grid or flex Container. For example, in the next pen, I have a set of items laid out with display: inline-block and this means that I get the ability to align the items even if the browser does not have Flexbox:
In this next pen, I have treated the inline-block as a fallback for Flex layout. The alignment properties no longer apply, and I can add align-items to align the items in Flexbox. You can tell that the Flexbox method is in play because the gap between items that you will get when using display: inline-block is gone.
Now that we do have better ways to align boxes in CSS (as we will look at in the next section), we don’t need to employ the vertical-align and text-align properties in places other than the inline and text elements for which they were designed. However, they are still completely valid to use in those text and inline formats, and so remember if you are trying to align something inline, it is these properties and not the Box Alignment ones that you need to reach for.
The Box Alignment Specification deals with how we align everything else. The specification details the following alignment properties:
You might already think of these properties as being part of the Flexbox Specification, or perhaps Grid. The history of the properties is that they originated as part of Flexbox, and still exist in the Level 1 specification; however, they were moved into their own specification when it became apparent that they were more generally useful. We now also use them in Grid Layout, and they are specified for other layout methods too, although current browser support means that you won’t be able to use them just yet.
Therefore, next time someone on the Internet tells you that vertical alignment is the hardest part of CSS, you can tell them this (which even fits into a tweet):
In the future, we may even be able to dispense with display: flex, once the Box Alignment properties are implemented for Block Layout. At the moment, however, making the parent of the thing you want centering a flex container is the way to get alignment horizontally and vertically.
The Two Types Of Alignment
When aligning flex and grid items, you have two possible things to align:
You have the spare space in the grid or flex container (once the items or tracks have been laid out).
You also have the item itself inside the grid area you placed it in, or on the cross axis inside the flex container.
I showed you a set of properties above, and the alignment properties can be thought of as two groups. Those which deal with distribution of spare space, and those which align the item itself.
Dealing With Spare Space: align-content And justify-content
The properties which end in -content are about space distribution, so when you choose to use align-content or justify-content you are distributing available space between grid tracks or flex items. They don’t change the size of the flex or grid items themselves; they move them around because they change where the spare space goes.
Below, I have a flex example and a grid example. Both have a container which is larger than required to display the flex items or grid tracks, so I can use align-content and justify-content to distribute that space.
Moving Items Around: justify-self, align-self, justify-items And align-items
We then have align-self and justify-self as applied to individual flex or grid items; you can also use align-items and justify-items on the container to set all the properties at once. These properties deal with the actual flex or grid item, i.e. moving the content around inside the Grid Area or flex line.
Grid Layout You get both properties as you can shift the item on the block and inline axis as we have a defined Grid Area in which it sits.
Flex Layout You can only align on the cross axis as the main axis is controlled by space distribution alone. So if your items are a row, you can use align-self to shift them up and down inside the flex line, aligning them against each other.
In my example below, I have a flex and a grid container, and am using align-items and align-self in Flexbox to move the items up and down against each other on the cross axis. If you use Firefox, and inspect the element using the Firefox Flexbox Inspector, you can see the size of the flex container and how the items are being moved vertically inside of that.
In grid, I can use all four properties to move the items around inside their grid area. Once again, the Firefox DevTools Grid Inspector will be useful when playing with alignment. With the grid lines overlaid, you can see the area inside which the content is being moved:
Play around with the values in the CodePen demo to see how you can shift content around in each layout method:
One of the cited issues with people remembering the alignment properties in Grid and Flexbox, is that no one can remember whether to align or to justify. Which direction is which?
For Grid Layout, you need to know if you are aligning in the Block or Inline Direction. The Block direction is the direction blocks lay out on your page (in your writing mode), i.e. for English that is vertically. The Inline direction is the direction in which sentences run (so for English that is left to right horizontally).
To align things in the Block Direction, you will use the properties which start with align-. You use align-content to distribute space between grid tracks, if there is free space in the grid container, and align-items or align-self to move an item around inside the grid area it has been placed in.
The below example has two grid layouts. One has writing-mode: horizontal-tb (which is the default for English) and the other writing-mode: vertical-rl. This is the only difference between them. You can see that the alignment properties which I have applied work in exactly the same way on the block axis in both modes.
To align things in the inline direction, use the properties which begin with justify-. Use justify-content to distribute space between grid tracks, and justify-items or justify-self to align items inside their grid area in the inline direction.
Once again, I have two grid layout examples so that you can see that inline is always inline — no matter which writing mode you are using.
Flexbox is a little trickier due to the fact that we have a main axis which can be changed to row or column. So, let’s first think about that main axis. It is set with the flex-direction property. The initial (or default) value of this property is row which will lay the flex items out as a row in the writing mode currently in use — this is why when working in English, we end up with items laid out horizontally when we create a flex container. You can then change the main axis to flex-direction: column and the items will be laid out as a column which means they are laid out in the block direction for that writing mode.
As we can do this axis switching, the most important factor in Flexbox is asking, “Which axis is my main axis?” Once you know that, then for alignment (when on your main axis) you simply use justify-content. It doesn’t matter if your main axis is row or column. You control space between the flex items with justify-content.
On the cross axis, you can use align-items which will align the items inside the flex container or flex line in a multi-line flex container. If you have a multi-line container using flex-wrap: wrapand have space in that container, you can use align-content to distribute the space on the cross axis.
In the example below, we are doing both with a flex container displayed as a row and a column:
The justify-content and align-content properties in Grid and Flexbox are about distributing extra space. So the thing to check is that you have extra space.
Here is a Flex example: I have set flex-direction: row and I have three items. They don’t take up all of the space in the flex container, so I have spare space on the main axis, the initial value for justify-content is flex-start and so my items all line up at the start and the extra space is at the end. I am using the Firefox Flex Inspector to highlight the space.
If I change flex-direction to space-between, that extra space is now distributed between the items:
If I now add more content to my items so they become larger and there is no longer any additional space, then justify-content does nothing — simply because there is no space to distribute.
A common question I’m asked is why justify-content isn’t working when flex-direction is column. This is generally because there is no space to distribute. If you take the above example and make it flex-direction: column, the items will display as a column, but there will be no additional space below the items as there is when you do flex-direction: row. This is because when you make a Flex Container with display: flex you have a block level flex container; this will take up all possible space in the inline direction. In CSS, things do not stretch in the block direction, so no extra space.
Add a height to the container and — as long as that is more than is required to display the items — you have extra space and therefore justify-content will work on your column.
Why Is There No justify-self In Flexbox?
Grid Layout implements all of the properties for both axes because we always have two axes to deal with in Grid Layout. We create tracks (which may leave additional space in the grid container in either dimension,) and so we can distribute that space with align-content or justify-content. We also have Grid Areas, and the element in that area may not take up the full space of the area, so we can use align-self or justify-self to move the content around the area (or align-items, justify-items to change the alignment of all items).
Flexbox does not have tracks in the way that Grid layout does. On the main axis, all we have to play with is the distribution of space between the items. There is no concept of a track into which a flex item is placed. So there is no area created in which to move the item around in. This is why there is no justify-self property on the main axes in Flexbox.
Sometimes, however, you do want to be able to align one item or part of the group of items in a different way. A common pattern would be a split navigation bar with one item being separated out from the group. In that situation, the specification advises the use of auto margins.
An auto margin will take up all of the space in the direction it is applied, which is why we can center a block (such as our main page layout) using a left and right margin of auto. With an auto margin on both sides, each margin tries to take up all the space and so pushes the block into the middle. With our row of flex items, we can add margin-left: auto to the item we want the split to happen on, and as long as there is available space in the flex container, you get a split. This plays nicely with Flexbox because as soon as there is no available space, the items behave as regular flex items do.
One of the things I think is often overlooked is how useful Flexbox is for doing tiny layout jobs, where you might think that using vertical-align is the way to go. I often use Flexbox to get neat alignment of small patterns; for example, aligning an icon next to text, baseline aligning two things with different font sizes, or making form fields and buttons line up properly. If you are struggling to get something to line up nicely with vertical-align, then perhaps try doing the job with Flexbox. Remember that you can also create an inline flex container if you want with display: inline-flex.
There is no reason not to use Flexbox, or even Grid for tiny layout jobs. They aren’t just for big chunks of layout. Try the different things available to you, and see what works best.
People are often very keen to know what the right or wrong way to do things is. In reality, there often is no right or wrong; a small difference in your pattern might mean the difference between Flexbox working best, where otherwise you would use vertical-align.
To wrap up, I have a quick summary of the basics of alignment. If you remember these few rules, you should be able to align most things with CSS:
Are you aligning text or an inline element? If so, you need to use text-align, vertical-align, and line-height.
Do you have an item or items you want to align in the center of the page or container? If so, make the container a flex container then set align-items: center and justify-content: center.
For Grid Layouts, the properties that start with align- work in the Block direction; those which start with justify- work in the inline direction.
For Flex Layouts, the properties that start with align- work on the Cross Axis; those which start with justify- work on the main axis.
The justify-content and align-content properties distribute extra space. If you have no extra space in your flex or grid container, they will do nothing.
If you think you need justify-self in Flexbox, then using an auto margin will probably give you the pattern you are after.
You can use Grid and Flexbox along with the alignment properties for tiny layout jobs as well as main components — experiment!
For more information about alignment, see these resources:
Charts form an integral part of any industry that deals with data. Charts are useful in the voting and polling industry, and they’re also great at helping us better understand the different behaviors and characteristics of the users and clients we work with.
Why are real-time charts so important? Well, they’re useful in cases when new data is produced continuously; for example, when using live-time series for visualizing stock prices is a great use for real-time charts. In this tutorial, I’ll explain how to build real-time charts with open-source technologies apt for exactly this particular task.
Note: This tutorial requires basic knowledge of React and GraphQL.
PostgreSQL The very point behind using Charts is to visualize “huge” volumes data. We, therefore, need a database that efficiently handles large data and provides an intuitive API to restructure it. SQL databases allow us to make views that abstract and aggregate data for us. We will be using Postgres which is a time-tested and highly efficient database. It also has fancy open-source extensions like Timescale and PostGIS which allow us to build geolocation-based and time-series-based charts respectively. We will be using Timescale for building our time series chart.
GraphQL Engine This post is about building real-time charts, and GraphQL comes with a well-defined spec for real-time subscriptions. Hasura GraphQL Engine is an open-source GraphQL server that takes a Postgres connection and allows you to query the Postgres data over realtime GraphQL. It also comes with an access control layer that helps you restrict your data based on custom access control rules.
For this tutorial, you will need the following on your system:
Docker CE Docker is a software that lets you containerize your applications. A docker image is an independent packet that contains software along with its dependencies and a minimalistic operating system. Such docker images can be technically run in any machine that has docker installed. You will need docker for this tutorial.
We will build the following live time series chart that shows the maximum temperature of a location in intervals of 5 seconds over the past 20 minutes from the present moment.
Setting Up The Backend
Running The Services
The backend comprises of a Postgres database, its timescale extension, and Hasura GraphQL Engine. Let us get the database and our GraphQL server running by running the respective docker images. Create a file called docker-compose.yaml and paste this content into it.
Note: docker-composeis a utility to run multiple docker images declaratively.
This docker-compose.yaml contains the spec for two services:
timescale This is our Postgres database with Timescale extension installed. It is configured to run at port 5432.
graphql-engine This is our Hasura GraphQL Engine instance, i.e. the GraphQL server that points to the database and gives GraphQL APIs over it. It is configured to run at the port 8080, and the port 8080 is mapped to the port 8080 of the machine that this docker container runs on. This means that you can access this GraphQL server through at localhost:8080 of the machine.
Let’s run these docker containers by running the following command wherever you have placed your docker-compose.yaml.
docker-compose up -d
This command pulls the docker images from the cloud and runs them in the given order. It might take a few seconds based on your internet speed. Once it is complete, you can access your GraphQL Engine console at http://localhost:8080/console.
Setting Up The Database
Next, let us create a table called temperature that stores the values of temperatures at different times. Go to the Data tab in the console and go to the SQL section. Create our temperature table by running this SQL block:
CREATE TABLE temperature (
temperature numeric not null,
location text not null,
recorded_at timestamptz not null default now()
This creates a simple Postgres table in the database. But we wish to leverage the time interval partitioning of the Timescale extension. To do this, we must convert this table into timescale’s hypertable by running the SQL command:
The GraphQL mutation above inserts a row in the temperature table. Now try to make a GraphQL query to check if the data was inserted.
Then try making a query:
Hope it worked 🙂
Now, the task at our hand is to create a live time-series chart that shows the maximum temperature of a location in intervals of 5 seconds over the past 20 minutes from the present moment. Let’s create a view that gives us exactly this data.
CREATE VIEW last_20_min_temp AS (
SELECT time_bucket('5 seconds', recorded_at) AS five_sec_interval,
MAX(temperature) AS max_temp
WHERE recorded_at > NOW() - interval '20 minutes'
GROUP BY five_sec_interval, location
ORDER BY five_sec_interval ASC
This view groups the data from the temperature table in 5-second windows with their max temperature (max_temp). The secondary grouping is done using the location field. All this data is only from the past twenty minutes from the present moment.
That’s it. Our backend is set up. Let us now build a nice real-time chart.
Hello GraphQL Subscriptions
GraphQL subscriptions are essentially “live” GraphQL queries. They operate over WebSockets and have exactly the same response structure like GraphQL queries. Go back to http://localhost:8080/console and try to make a GraphQL subscription to the view we created.
This subscription subscribes to the data in the view where the location is London and it is ordered in ascending order of the five_second_intervals.
Naturally, the response from the view would be an empty array because we have not inserted anything in the database in the past twenty minutes. (You might see the entry that we inserted sometime back if you reached this section within twenty minutes.)
Keeping this subscription on, open another tab and try inserting another value in the temperatures table using the same mutation that we performed earlier. After inserting, if you go back to the tab where the subscription was on, you would see the response having updated automatically. That’s the realtime magic that GraphQL Engine provides. Let’s use this subscription to power our real-time chart.
Getting Started With Create-React-App
Let us quickly get started with a React app starter using create react app. Run the command:
npx create-react-app time-series-chart
This will create an empty starter project. cd into it and install the GraphQL and chart libraries. Also, install moment for converting timestamps to a human-readable format.
npm install --save apollo-boost apollo-link-ws subscriptions-transport-ws graphql react-apollo chart.js react-chartjs-2 moment
Finally, run the app with npm start and a basic React app would open up at http://localhost:3000.
Setting Up Apollo Client For Client-Side GraphQL
Apollo client is currently the best GraphQL client that works with any GraphQL compliant server. Relay modern is good too but the server must support the relay spec to leverage all the benefits of Relay modern. We’ll use Apollo client for client-side GraphQL for this tutorial. Let us perform the setup to provide Apollo client to the app.
I am not getting into the subtleties of this setup because the following code snippets are taken directly from the docs. Head to src/index.js in the React app directory and instantiate Apollo client and add this code snippet above ReactDOM.render.
import WebSocketLink from 'apollo-link-ws';
import ApolloClient from 'apollo-client';
import ApolloProvider from 'react-apollo';
import InMemoryCache from 'apollo-cache-inmemory';
// Create a WebSocket link:
const link = new WebSocketLink(
const cache = new InMemoryCache();
const client = new ApolloClient(
Finally, wrap the App inside ApolloProvider so that we can use Apollo client in the children components. Your App.js should finally look like:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import WebSocketLink from 'apollo-link-ws';
import ApolloClient from 'apollo-client';
import ApolloProvider from 'react-apollo';
import InMemoryCache from 'apollo-cache-inmemory';
// Create a WebSocket link:
const link = new WebSocketLink(
const cache = new InMemoryCache();
const client = new ApolloClient(
Apollo client has been set up. We can now easily use real-time GraphQL from our App. Head to src/App.js.
Building The Chart
ChartJS provides a pretty neat API for building charts. We will be building a line chart; so a line chart expects data of the form:
Let us use one such Subscription component to subscribe to our view and then transform the subscription data to the structure that ChartJS expects. The transforming logic looks like this:
let chartJSData =
label: "Max temperature every five seconds",
const humanReadableTime = moment(item.five_sec_interval).format('LTS');
Note: You can also use the open-source library graphq2chartjs for transforming the data from GraphQL response to a form that ChartJS expects.
After using this inside the Subscription component, our App.js looks like:
import React, Component from 'react';
import Line from 'react-chartjs-2';
import Subscription from 'react-apollo';
import gql from 'graphql-tag';
import moment from 'moment';
const TWENTY_MIN_TEMP_SUBSCRIPTION= gql'
class App extends Component
style=display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '20px'
(data, error, loading) =>
let chartJSData =
label: "Max temperature every five seconds",
const humanReadableTime = moment(item.five_sec_interval).format('LTS');
animation: duration: 0,
scales: yAxes: [ticks: min: 5, max: 20 ]
export default App;
You will have a fully working real-time chart ready at http://localhost:3000 . However, it would be empty, so let’s populate some sample data so we can actually see some magic happen.
Note: I have added some more options to the Line chart because I don’t like those fancy animations in ChartJS. A time series looks sweet when it’s simple, however, you can remove the options prop if you like.
Inserting Sample Data
Lets write a script that populates our database with dummy data. Create a separate directory (outside this app) and create a file called script.js with the following content,
Fallbacks can be defined as an alternative plan that may be used, and in the context of user journeys, they would be an alternative path to the expected or planned user behavior. So, when we think about our sites and apps, we build them with a particular plan in mind to achieve a particular goal by taking a particular route and to experience a particular experience.
If you are experienced in building products, you will know that users have a tendency to do things you didn’t plan for, and that’s alright because we can’t possibly understand all of their needs and intention. This is why fallbacks are so valuable.
Over the years, we have tried and tested many tools at Venture Harbour to help us get better feedback loops. Our products have needs which require different types of tools to reveal all kinds of insights. From heatmaps and visitor recording tools (like Hotjar and Fullstory) to analytics platforms like Google Analytics and Amplitude.
These tools are great and help us accomplish a lot, but they only go so far. We now need to get deeper insights that can only be achieved by implementing fallbacks to your user journeys.
To start, we need to be thinking about what alternative behaviors or routes our users might experience that we didn’t see coming. Here are three common fallbacks:
Dead Ends The user’s journey has come to an end, and there are no clear or onward steps. The goal would be to offer the next steps to the user and track those choices.
Grey Areas The user is interacting with your site or app, but we have little or no understanding of what is going on, or why they are doing what they are doing. The goal is to shed light on those areas to learn about what might be happening.
Errors The user is presented with an error message that gives insufficient context. The goal here is to offer context by interacting with the user to gain feedback from them.
Let’s dive into some examples from the wild in which feedback loops are missing from popular fallbacks. Then, I will follow up with ideas of how that feedback loop might look and work in those fallbacks.
Note: Just so you know, these are mockups based on real-world scenarios.
Turning Dead Ends Into Feedback Goldmines
Dead ends in a user flow are common. One way of discovering them is by analyzing your Exit Pages in your analytics tracking tool, like Google Analytics. This will highlight common exit pages on your site or app and give you a starting point to start investigating.
Now we need to be asking the simple question:
“Why are users leaving at these points?”
Take a look at the actual pages these exits are happening on and start considering at what point in the process of using your app or site the user is at when they hit this dead end. Are they just getting started, are they mid-flow, or are they close to achieving a particular goal in the journey? These considerations will help you paint a better picture of the user’s situation and possible reasons.
Example: Dead Ends In Search
A very common dead end is with search when you are searching for something and you are shown that “No Results” page. Businesses are starting to really invest in these pages, and you will find that you would normally be shown some sort of a result — especially on e-commerce sites.
When searching for anything, we should at least return some sort of result. When we don’t have an actual result to show, then we need to creatively think about how to capitalize on these scenarios. This can take the form of a question or a common action that could have possibly been the intention of the user’s search in the first place.
Below is an example of a dead-end search:
In this case, what can we find out from the user that we don’t already know to help us improve their experience and help us learn? What questions could we be asking them? What could we provide the user at this point, now that they haven’t found what they are after?
This particular scenario is interesting, and I thought of a couple of ideas on how to get information from the user to help us improve our app and provide them with the next step.
As shown below, we start off by telling the user that what they are looking for isn’t available now, but could be in the future. In return, we can get some feedback on what they had hoped to do or find instead:
We could then provide the user with a next step by offering them a filter that will help them find an alternative and subsequently inform us of what category of extension they were searching for, which we could then review and work out what categories we should be investing time in. With this information collated from the user, we can start to build up a knowledge base of what users might expect in these scenarios and begin to suggest smarter categories and suggestions to the end user in the future. That way, we can provide them with a much better user experience.
Example: Natural Dead Ends
Dead ends can also happen as a natural order of your site or app. There might be scenarios in which users are met with a page that lacks content and no onward step due to the system not having had time to process data. Or maybe the data has not been created yet, as illustrated below:
So now what we want to do is make sure of two things:
The user should understand why and what’s going on;
Engage the user while they wait for the data.
Below is a friendly, valuable and useful fallback for both the user and for ourselves. The user is offered notifications to be sent to their email address — along with a month’s subscription free of charge! In return, we get to inform users when to come back to the app: happy users with a free month, and extra data on the users themselves. It’s always best when everyone wins!
Over time, we can start to understand if the majority of users do or do not want to have certain features, and whether they prefer to start turning them on by default or removing them completely. Also, information from surveys can help grow our understanding of users’ expectations of the app, and help us shape it to fit users’ needs.
What I mean by ‘grey areas’ are areas that lack insight and clarity on what users might be doing or why users are making particular decisions. These are normally areas that aren’t of high priority to the site/app but are part of the key user journey. The more data we have through the user journey, the better we can understand the whats, whys and hows of users’ actions.
Example: Understanding Your “Other”
It is quite common practice to label something as ‘other’ when there isn’t a clear fit. Below is an example of this kind of UI, and as we analyze this scenario, it is clear that the only insight we have is that we know that the user is labeling this as a ‘other’ type, and that leaves us with little understanding of what it is or what they intended it to be.
Of course, we could investigate a little more about what is being labelled as ‘other’ and find some common lines, but we wouldn’t know what the user might have intended by labelling it that.
So, how can we change this scenario from being just another ‘other’ answer to something that is informative and useful to both user and us? An approach I would suggest is a little more complex but will make the experience a lot more engaging.
We want to allow users to either choose their option by clicking on the option that they know they want or by searching for what they think they are looking for. Why is this helpful? Well, when it comes to naming options, we might name them in quite a different way compared to how the user might have in mind. But if we still can’t offer the user an answer they’re looking for, then we should start a conversation with them by showing them a question and a text box, and ask them what it is that they are looking for and why. (Perhaps also add a line that we will follow up with them and find a solution to their needs.)
As we start to find common threads in the searches and responses we get, we can start to adjust the search to serve the user the option the most likely need, and we can also build new features as demand increases, too.
Example: Understand You Instant Search
Another grey area below is one example of myself using an instant search while looking for some keywords that are not associated with anything I have in my account.
From this experience, I asked myself the following questions:
What’s the takeaway from this scenario?
Can I find out how common this scenario is?
What is the user trying to achieve?
How can we help them get to where they want?
Below is the ‘No Results’ results window with a feedback loop to help us learn about the users’ needs. The search results are populated in a way which can bring insights into the users’ needs, and provide us with at least some clarity into what exactly it is that they are searching for with the ‘search in’ option.
A few ways to engage your users would be:
Offer common actions on your site or app for the user to create the content that they are looking for;
Provide the option of them receiving a notification once the thing they had been looking for becomes available (this is a nice way to bring the user back at a later stage);
Allow them to give straightforward feedback because sometimes talking to someone will solve everything (and a conversation is the best source of feedback).
We can learn and get smarter with the results we get from this feedback loop, as long as we start providing smarter category suggestiony to our users. Over time, personalized habits can be learned for individual users and we can start to suggest options that are more likely to resonate with that user because of their past actions and searches.
Make Your Errors Messages A Strength
Whether we choose to accept it or not, errors do happen. When they happen, we should know about them, but sometimes we can cater for errors in a generic way which doesn’t help us or the user.
An example of this is when the user could be interacting with your site or app where they are saving some sort of data to your system, but for some reason, the connection is lost and the process fails. There is little to diagnose what is going on or what has happened but we know there was an error. Standard procedure is to inform the user that an error has occurred and possibly to try again.
When we know little about the issue on our end, or that it could have been caused by a handful of things, then this is a great opportunity to get back some feedback from the user about what’s going on. I think this is the most simple fallback to implement, but one that I see the least of.
A typical scenario would be when something is being automatically saved while you are using the site or app. This is a growing scenario especially with mobile connections; understanding that your site is used by users on-the-go or on a mobile connection is a great insight, and we should try to gather that information as much as possible.
Or you could make it even simpler for the user. If you already have an idea of what the issue may be and would like to get a better idea of how often it has happened to the user, then serve them with options but still allow them to tell you what they’ve experienced. Once you have that information, you can then start investing your time in possible new features to help resolve those given issues and hopefully find yourself not having to show an error message at all.
Something important to remember is that a fallback doesn’t have to be a permanent feature, but it can be a temporary one to help you figure out what to ask or what to build next. It requires a little bit of investment and time to collect data, but these can be seen as test running in areas of your user journey that you have never looked into before, and will only add to the understanding of your users and their needs.
With all of this said, fallbacks in an ideal world would never exist. If you are working on a brand new project or reworking your user flow, set yourself the challenge of creating a flow where a user would never encounter scenarios like these. Consider how to prevent a user from ever searching for something that doesn’t exist. Track and analyze all areas of your user journey to understand each of their steps and formulate ways where an error message would never be shown.
Fallbacks will look different depending on your product, as you will be asking different questions and offering different options, but they will all play a valuable role in exposing yourself and the users to better options and understanding.
Why not take a few hours to look at your user journeys and document where the grey areas are, as well as look for dead ends and error messages that (still) exist in your product.
Here are some guides to get you started:
Dead Ends Start exploring your analytics and — if you aren’t already — get comfortable in there. The exit pages are normally tracked by default and will provide you with great insights to what stage your users are leaving the site. Think about where your users will be in their journey and consider the kind of needs they might have at those points.
Grey Areas If you haven’t already, map out your user journey and start highlighting areas that you might have questions about. Consider the points in which your users are making decisions and think about the options you are giving them. Remember the “Other” option and think about where there might be any that are quite generic. Start tracking those options to see how often they are chosen, then start exploring the ways to get feedback from the users on what they want.
Errors You can quickly work out where an error might be shown on your app. With a site/app that is saving, updating and working in real time, errors are possibly a key part to your system. Start by figuring out which area is most used, which could result in where errors are most frequently seen. Invest in the error messages there and start gathering feedback on why those are being shown — both from your system but also the user. I would also recommend creating a default error message with a feedback loop that would be used across the site for any new feature so that you will start learning from those errors from day one.
Sometimes best practices for nonprofit websites seem obvious, but let’s begin with a story that illustrates how fundamental these features are for success.
For years a neighborhood association asked members to join and renew at its 4th of July parade. But not everyone attended the parade or reached the membership table. The association had a PayPal button for dues payments on their website, but no one was automatically reminded to renew. As the parade outreach effort faltered, the organization resorted to inconsistent, volunteer-led member retention efforts.
After setting up membership software with automatic recurring credit card payments, the association quickly doubled its renewal rate. They were also shocked to see that many members also opted to add on significant additional recurring donation amounts beyond their dues payment. Making this one change possibly saved the association from extinction.
Recurring donations or memberships
Nonprofits with paper membership processes or PayPal donate buttons are losing significant revenue. Certainly setting up membership management software requires time and resources. But proceeds from auto-recurring payments and one-time renewal payments spurred by automatic reminders should more than compensate. Be sure to set up multiple past due/failed payment reminders in your system to accommodate today’s distracted members.
Email list signup
The people most likely to become donors and members are those already on your prospect email list. Set up an account with MailChimp or another email marketing platform. MailChimp is free for up to 2000 subscribers as long as you send less than 12,000 emails per month. Add an email signup widget to your website.
Automated blog post emails or an e-newsletter
Nonprofits that are volunteer-run or short-staffed find it hard to draft a regular e-newsletter. But how else will members know what you are doing for them? In some cases, writing blog posts that are automatically sent to your email list is better than an e-newsletter because:
A post doesn’t need to be designed in an email marketing platform. Information reaches your subscribers sooner.
If your recipients are just as likely to open one email from you as another, why put so much effort into an e-newsletter?
Headlines from your blog posts (which should be your email subject line) are more click-worthy than a subject line like, “Our Monthly Newsletter.”
But be careful not to send communications too often or you risk unsubscribes. Check your unsubscribe rate after each mass email.
Pictures and good design
Like the adage says, “A picture is worth 1000 words.” Your current and prospective donors and members want to see themselves as part of an energetic organization. Pictures are the best way to tell that story. You have around seven seconds to prove to visitors that your site is worth exploring. Consider running a usability test to be sure you are doing a good job.
Members only content or benefits
Members join because they want to belong, but benefits play a role. Your welcome and renewal emails should link to a page where you list all of your benefits. Create content such as articles or a member directory that only members can see. Offer events or tickets just for donors. Your membership software should allow you to limit access to specific pages, posts and events.
Donors may be diverse in term of age, education and tech savviness, so offer them different ways to connect. Older donors like to reach out by phone, while younger members may want to be able to message you on Facebook. Meet members and where they are, but only if staff can fully support each method (such as regularly posting on Facebook or having set times when you are answering the phone).
Events — in person or virtual — are a core function of most nonprofits. Your membership software should support online event registration and payments. If your site is in WordPress, your system may offer widgets to promote a list of upcoming events in the site-wide sidebar or footer.
Is it clear what action you want a first time or returning website visitor to take? If the main goal is driving membership, there should be a benefits list on the home page as well as a Join button. Ask friends to look at the home page. Can they accurately answer, “What is the primary action we are asking you to take?