Web Standards

The peculiar magic of flexbox and auto margins

Css Tricks - Fri, 07/27/2018 - 9:55am

In front-end development, there are often times when I know that I don’t know something. I might know enough to know what CSS to search for, but I have absolutely no idea how to use it or what the right syntax is. Somehow, in my head, there appears to be a filing cabinet that’s entirely empty, and when I try to look something up, all I find is an almost illegible sticky note instead.

One topic like this (which is an area I’ve sort of always known about but never really understood) is how auto margins and flexbox interact with one another.

Take this example for instance:

.parent { display: flex } .child { margin: auto; }

What does this do again? I seem to recall there’s a bunch of nifty things you can do with it, and earlier this week, I half-remembered them after reading a great post by Sam Provenza from a while back that shows how auto-margins and flexbox work together. But I still didn’t quite get the concept even after reading that post, and it wasn’t until I started making demos of my own that it started to click.

In that post, Sam describes how margin: auto impacts flex items like so:

If you apply auto margins to a flex item, that item will automatically extend its specified margin to occupy the extra space in the flex container, depending on the direction in which the auto-margin is applied.

Let's pick that apart a bit and say we have a simple parent div with a child div inside it:

<div class="parent"> <div class="child"></div> </div>

And let's assume we’re using the following CSS to style those divs:

.parent { display: flex; height: 400px; background-color: #222; } .child { background-color: red; width: 100px; height: 100px; }

The result is something like this:

See the Pen margin-auto: #1 by Robin Rendle (@robinrendle) on CodePen.

When we add margin-left: auto to the .child element like so:

.child { background-color: red; width: 100px; height: 100px; margin-left: auto; }

...then we’ll see this instead:

See the Pen margin-auto: #2 by Robin Rendle (@robinrendle) on CodePen.

Weird, huh? The left-hand margin is pushing the parent so that the child is nestled up in the far right-hand corner. But it gets a little weirder when we set all margins to auto:

.child { background-color: red; width: 100px; height: 100px; margin: auto; }

See the Pen margin-auto: #3 by Robin Rendle (@robinrendle) on CodePen.

It’s like we're using a popular centering trick by setting justify-content and align-items to center because the child decides to rest in the center of the parent, both horizontally and vertically. Likewise, if we set margin-left and margin-top to auto, then we can let the flex item push itself into the bottom-right of the parent:

See the Pen margin-auto: #4 by Robin Rendle (@robinrendle) on CodePen.

When Sam says, "that item will automatically extend its specified margin to occupy the extra space in the flex container," the way my empty filing cabinet brain interprets that is like so:

Setting the margin property on a flex child will push the child away from that direction. Set margin-left to auto, the child will push right. Set margin-top to auto and the child will push to the bottom.

After I write that down, it sounds so obvious to me now that it’s almost foolish but sometimes that’s what it takes to get a new concept to stick in my big dumb spongey noggin.

Why is this useful to know? Well, I think there are a few moments where justify-self or align-self might not get you exactly what you want in a layout where using auto margins gives you that extra flexibility to fine-tune things. A lot of demos I’ve seen out there, including the ones Sam made for her original post, mostly appear to be for aligning navigation items in a menu. So, pushing one item in that menu to the bottom or far right of a flex parent is certainly useful in those scenarios.

Anyway, I think this weird trick is important to remember, just in case.

The post The peculiar magic of flexbox and auto margins appeared first on CSS-Tricks.

Stuff you can do with CSS pointer events

Css Tricks - Fri, 07/27/2018 - 8:05am

Martijn Cuppens (the same fella with the very weird div!) has some more irresistible CSS trickery. Three of the examples are about making a child element trigger an event on a parent element (almost like the magic that is :focus-within).

Here's how I reasoned it out to myself:

  1. You know how if you display: hidden; an element, even if you display: block; a child, it doesn't matter — it's hidden because its parent is hidden.
  2. The same is not true for visibility: hidden;. Children will be hidden because visibility inherits, but if you visibility: visible; them, they become visible again.
  3. That's what is happening here with pointer-events. If you pointer-events: none; on a parent and then pointer-events: auto; on a child, you're re-enabling pointer events. Then a :hover on a parent will be triggered (for example), when hoving the child, but nowhere else inside the parent.

And don't miss pointer-events: visiblePainted; &#x1f633;

Direct Link to ArticlePermalink

The post Stuff you can do with CSS pointer events appeared first on CSS-Tricks.

Sometimes `sizes` is quite important.

Css Tricks - Fri, 07/27/2018 - 4:26am

Paraphrased question from email:

I just read your article Responsive Images: If you’re just changing resolutions, use srcset. In the age of "responsive websites," srcset does not help in certain situations. For example, I have a popular products slider. On mobile, I have one image per slide where the images are 320px wide. On desktop, I have six images per slide where each is 160px wide. So the desktop images are smaller on desktop, not bigger.

How do I handle this situation with srcset?

I tried to be careful with that post title: "If you’re just changing resolutions, use srcset." In this case, we're changing the size of the images not just at certain resolutions, but at specific breakpoints as well, which means we're also going to need to use the sizes attribute to get the most out of responsive images. The entire job of the sizes attribute is to tell the browser what size the image will be shown at, as per our CSS.

A demo! Resize the width to see it alternate between the "Desktop" and "Mobile" views.

See the Pen Responsive Images Slider by Chris Coyier (@chriscoyier) on CodePen.

As the email mentioned, the "Desktop" version actually renders the images smaller (160px) than the "Mobile" version (320px).

Let's also account for 2x displays. To prepare ourselves, let's have three versions of each image:

  • 160px (for 1x desktop displays)
  • 320px (for 2x desktop displays, or 1x mobile displays)
  • 640px (for 2x mobile displays)

With srcset, that looks like this:

<img srcset=" food-big.jpg 640w, foot-medium.jpg 320w, food-small.jpg 160w" />

Notice we're not yet using the sizes attribute. Browsers will assume you're probably going to render this image at 100vw wide. That's unfortunate because the browser may download a larger image than it needs, which is what we're trying to fight against with responsive images in the first place.

On my 2x desktop display, I can tell it's downloading the 640px version, but it really only needs the 320px version.

It's our CSS that controls how big these images render. In fact, we have a media query in this demo that says, "Hey browser, only render the images at 160px wide on Desktop displays."

@media (min-width: 600px) { .slider img { width: 160px; } }

You'd think the browser would know that, and it does — it just needs to download and parse the CSS first. The browser wants to make a decision about what to download faster than that. So, let's tell it with the sizes attribute.

<img srcset=" food-big.jpg 640w, foot-medium.jpg 320w, food-small.jpg 160w" sizes="(min-width: 600px) 160px, 320px" />

That's saying, "OK, we'll be rendering this image 160px wide on Desktop. Otherwise, let's go with 320px wide." With that in place, we can see the browser is making the right choice:

The browser is now only choosing to download the 320px version, which is correct on a 2x display where the images are being rendered at 160px.

And just to be sure, here's a narrow viewport (like "mobile" would be):

We're back to downloading the 640px version, which is correct, since at this viewport size, the sizes attribute is telling the browser we intend to render at 320px and we're on a 2x display. There is even more nuance here

I showed this demo to Eric "Sizes Master" Portis, who confirmed all this, but had some browser-specific things to add. I'll summarize (but note the date of this blog post because these things tend to change):

  • Firefox does exactly as described above.
  • Chrome does too, except that it will always use the larger version if it has that version in cache. So, if it has a 640px version in cache, it knows it really only needs a 320px version, but since it doesn't have a 320px version in cache, it'll use the 640px version instead.
  • Safari does too, except that after it has made its choice, it never changes (like if you resize the browser window).
  • An interesting part about srcset is that the spec allows it to make choices however it wants, perhaps using stuff like network conditions to decide. Most browsers don't do anything like this yet, except Chrome which downloads the smallest resource should it get a Save-Data header on the HTML document.
  • Joe McGill also noted: "For older iOS devices that don’t support w descriptors in srcset, the first source item in the list will be used, so you may want to lead with your preferred default size if you're supporting legacy iOS devices." In other words, those older iOS devices may have supported earlier syntaxes of responsive images, but only with x descriptor (like big-image.jpg 2x), so perhaps specify a good default image as the first in your srcset.

It might be helpful to look at Eric's fork to more easily see what gets downloaded:

See the Pen Responsive Images Slider by Eric Portis (@eeeps) on CodePen.

Random notes
  • I snagged those food photos from Unsplash.
  • I uploaded them to Cloudinary so that I could use URL params to resize them instead of having to deal with that myself.
  • They are all squares, not because I downloaded them like that, but because I sized them that way in CSS and prevented squishing with object-fit. That means image data is being downloaded that isn't needed, so I either should have cropped them myself or used Cloudinary URL params to do that.
  • I used the Pug HTML preprocessor for my demo just to reduce code repetition.

This is easier to look at:

img(srcset=` ${img_base}w_640${img_1} 640w, ${img_base}w_320${img_1} 320w, ${img_base}w_160${img_1} 160w, ` sizes=sizes)

...than the output:

<img srcset=" https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_640/v1531407936/robin-stickel-82145-unsplash_qnexwz.jpg 640w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_320/v1531407936/robin-stickel-82145-unsplash_qnexwz.jpg 320w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_160/v1531407936/robin-stickel-82145-unsplash_qnexwz.jpg 160w, " sizes="(min-width: 600px) 160px, 320px"/><img srcset=" https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_640/v1531407936/cel-lisboa-60315-unsplash_qsji9j.jpg 640w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_320/v1531407936/cel-lisboa-60315-unsplash_qsji9j.jpg 320w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_160/v1531407936/cel-lisboa-60315-unsplash_qsji9j.jpg.jpg 160w, " sizes="(min-width: 600px) 160px, 320px"/><img srcset=" https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_640/v1531407936/charles-deluvio-466056-unsplash_ocd3dh.jpg 640w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_320/v1531407936/charles-deluvio-466056-unsplash_ocd3dh.jpg 320w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_160/v1531407936/charles-deluvio-466056-unsplash_ocd3dh.jpg.jpg 160w, " sizes="(min-width: 600px) 160px, 320px"/>

The post Sometimes `sizes` is quite important. appeared first on CSS-Tricks.

Teaching Your Clients How to Use The Website You Built Them

Css Tricks - Thu, 07/26/2018 - 12:11pm

I share my own thoughts on how you might go about educating someone you just built a site for. But it turns out I had a lot of fun putting together a ton of other people's thoughts as well. I tweeted about it and got a flood of responses, so this article is an amalgamation of all that.

Direct Link to ArticlePermalink

The post Teaching Your Clients How to Use The Website You Built Them appeared first on CSS-Tricks.

Recent Videos!

Css Tricks - Thu, 07/26/2018 - 12:10pm

I've recorded a decent number of videos lately, most of which are pairing with someone and digging into a topic as I glean as much information as I can! Several of these are sponsored, in that they are a part of an advertising package. Hopefully, you know me well enough that I don't work with companies I don't like or that sell something I don't think you'd be good buying, but hey, heads up.

Phil Hawksworth and I do a couple of videos introducing the power of Netlify

Sarah Drasner and I get into coding with Vue

I do a little explanation of one reason I really like Jetpack: security

David Wells and I talk about serverless technology in a two-parter

I introduce CodePen to the gang at freeCodeCamp

The post Recent Videos! appeared first on CSS-Tricks.

Solved with CSS! Logical Styling Based on the Number of Given Elements

Css Tricks - Thu, 07/26/2018 - 4:06am

This post is the third in a series about the power of CSS.

Article Series:
  1. Colorizing SVG Backgrounds
  2. Dropdown Menus
  3. Logical Styling Based On the Number of Given Elements (this post)

Did you know that CSS is Turing complete? Did you know that you can use it to do some pretty serious logical styling? Well you can! You don’t have to set all of your logic-based styling rules in JavaScript, or even have to use JavaScript to set classes you are styling against. In many cases, CSS can handle that itself. I’m still discovering new CSS tricks everyday, and it just makes me love it even more.

This year, I started working at Bustle Digital Group. In media, as with a lot of products, the engineering team builds a platform that should support all use cases. Our CMS provides capabilities for authors and editors to create articles as well as curate pages, and control ad injection.

Unlike working with a static site, the engineering team doesn’t have full control over what data comes in from the user, so design decisions and governing rules must be made for a good user experience. Some of these scenarios we’ve faced in the digital media space have really inspired me to look into ways of using CSS to solve those UI challenges, and that’s when solutions involving this idea really came into my periphery.

So let’s take a look at some examples!

Example 1: Binary States

An often forgotten and very useful selector is the :empty pseudo selector. It allows you to style elements based on if they contain any content, or if they don’t. Hello empty states! Empty states are a great way to reach out to your users and show personality in your app, and you can inject that personality right from your CSS.

In this example, we have any list from a user. This could be posts the user has published (as an author), or bookmarked articles a user has saved (as an editor). The use cases are really endless here. Instead of injecting JavaScript, we can use pseudo elements to inject images, styles, and text:

Drawings illustrate conditionally applied styles based on no items (left) versus displayed items (right) in the list.

Our solution here is a mere three lines of code:

div:empty:after { content: 'oh no...'; }

You can also add a :before pseudo element to inject images or any other content you may want. Alternatively, the :not pseudo selector may be used in combination with :empty to create a :not(:empty) rule and style all elements which are not empty, and therefore do contain children.

See the Pen Empty States by Una Kravets (@una) on CodePen.

Note: This demo is for display purposes only. It is not advised to put content in pseudo elements for accessibility purposes. You can use the same technique of targeting :empty or :not(:empty) elements to apply styles to child elements that are more accessible to screen readers.

Advanced Numeric Selection

That was a nice soft ball example, but we can get much more complex than this binary choice of child elements in CSS, and to do this, we will use the :nth-child pseudo selector! CSS-Tricks has a great tool to help you test and play around with the :nth-child selection, and it can really come in handy as some of the examples will show you.

But before we get into those, how exactly does this work?

The meat of the code is this, with div standing in for any given sibling element, and x standing in for the number we are using to determine style breaks:

div:first-child:nth-last-child(n + x), div:first-child:nth-last-child(n + x) ~ div

Using :nth-last-child instead of using :nth-child for selection allows us to start from the end of a series instead of from the beginning. When we select :nth-last-child(n + x), we are selecting the x value starting from the end. If x = 3 that would look like this:

Illustration of how :nth-last-child(3) selects the third item from the end of the list.

Now, if we want to count values of n + 3, we are selecting all items that match 3 or more than 3 from the end. Starting with n = 0 (which would mean 0 + 3, and the 4th item being the first from the end after 3). It looks like this:

Illustration of how :nth-last-child(3) selects all items that match 3 or more than 3 from the end.

This is a great start, but the idea here is to conditionally style all of the items based on how many exist. So we need to work with these conditions but select all of the items. Let’s start with selecting the first item. We need to make a condition to see if the entire selection qualifies for the styling, and then start with that first sibling:

Uh oh. We only have the first item selected at this point, and we want to select all of the items. Luckily, we can use the super handy adjacent sibling selector (~) for that!

Adjusting our last example to :first-child:last-child(n + 3) ~ * selects all items excluding the first like we want.

Well, now you can see all of the items that follow the first item are selected, but we’re missing the first one, so we need to use two selectors, and thus the final answer becomes:

Combining both of the previous two examples will select all items in the list. Example 2: List Formatting

Say you want to list some credits at the end of an article. You’ve got some space to fill, and most articles have a small number of credits, but there are those exceptions that have a high production value and a lot of people involved in the making of them. We want to make sure both of these are good visual experiences, and can do that with CSS alone.

Here’s the plan: if there are four or fewer credits, list them in bullet format. Let them take up vertical space to fill the block appropriately. Once we have five or more credits listed, let’s turn that list into a horizontal format to not get too overwhelming for a reader. This is a small credits box after all!

Illustrations of a vertical unordered list (left) and a horizontal list separated by semicolons (right).

We can check out the number of elements we have available and style them as block elements until we hit our cap. At that point, we’ll switch to inline styling, and add a pseudo element to visually break up the data.

/* 5 or more items display next to each other */ li:first-child:nth-last-child(n + 5), li:first-child:nth-last-child(n + 5) ~ li { display: inline; } /* Adds semicolon after each item except the last item */ li:first-child:nth-last-child(n + 5) ~ li::before { content: ';'; margin: 0 0.5em 0 -0.75em; }

:nth-first-child:nth-last-child(n + 5) allows us to state: "start with the first child and apply styling to that child and every sibling after it if the original child matches having five or more siblings."" Is that confusing? Well, it works.

li:first-child:nth-last-child(n + 5) selects the first list item, and li:first-child:nth-last-child(n + 5) ~ li selects each list item following the initial one.

See the Pen vrQBMv by Una Kravets (@una) on CodePen.

Example 3: Conditional Carousel

Using this technique, let’s style a carousel to be responsive. At a large size, you want it to be centered in the middle of page when it has three items within it. But when it has enough items to fill the screen horizontally, let it be left-aligned for the user to swipe through it.

Illustrations of a carousel with three items (left) and more than three items (right).

What we can do here is stretch the elements to fit the screen unless we have too many elements and they would require an overflow. At that point, let’s go all-in on this overflow and really showcase the carousel capabilities by signaling scroll-ability with arrows and by increasing the margin between items. On top of that, let’s add a sticky arrow button to show that we can scroll through the elements and can tie JavaScript events to make the carousel scroll.

We can do the same thing as above in terms of the technique, but we will also use only the first-child to detect an arrow div and display it in the UI. The HTML would look like this:

<ul> <li> <div class="box">1</div> </li> <li> <div class="box">2</div> </li> ... <button class="arrow">——></button> </ul>

It’s not ideal to have empty elements in the DOM, but work with me. It’s still a clever hack. We’ll style the .arrow button to be invisible to the DOM and to screen readers with visibility: hidden unless the conditions apply (in this case, if four or more items are present). At that point we’ll give it a visible display (display: block), style, and position it appropriately:

li:first-child:nth-last-child(n + 5) ~ .arrow { display: block; position: sticky; ... }

See the Pen Box Alignment by Una Kravets (@una) on CodePen.

More Information!

In my research for this post, I discovered an excellent post by Heydon Pickering about this technique, called Quantity Queries, and another example by Lea Verou! In the comment thread of Heydon’s post, Paul Irish notes that this is a slower way of selecting elements, so maybe use it with caution.

The post Solved with CSS! Logical Styling Based on the Number of Given Elements appeared first on CSS-Tricks.

Visual. Intuitive. Unlike Anything Else.

Css Tricks - Thu, 07/26/2018 - 4:00am

(This is a sponsored post.)

monday.com is a team management tool that’s found favor with more than 34,000 teams, including teams of two to teams of 2,000+, teams working for startups, and teams working on projects for Fortune 500 companies like AOL, Adidas, Samsung, and the Discovery Channel to name several.

monday.com is so easy to use, and its dashboard displays make such a superb use of color that it’s every bit as popular with non-tech oriented teams as it is with their tech oriented counterparts. In fact, roughly 70% of this team management tool’s users can be classified as non-tech users.

Direct Link to ArticlePermalink

The post Visual. Intuitive. Unlike Anything Else. appeared first on CSS-Tricks.

7 Tips For Creating A Winning Mobile App Payment Screen

Usability Geek - Wed, 07/25/2018 - 10:58am
There is a principle of “give before you take” with apps. If you want your users to do something, such as rate the app, allow notifications, or make a purchase, you should give them value...
Categories: Web Standards

7 Tips For Creating A Winning Mobile App Payment Screen

Usability Geek - Wed, 07/25/2018 - 10:58am
There is a principle of “give before you take” with apps. If you want your users to do something, such as rate the app, allow notifications, or make a purchase, you should give them value...
Categories: Web Standards

Build a state management system with vanilla JavaScript

Css Tricks - Wed, 07/25/2018 - 3:36am

Managing state is not a new thing in software, but it’s still relatively new for building software in JavaScript. Traditionally, we’d keep state within the DOM itself or even assign it to a global object in the window. Now though, we’re spoiled with choices for libraries and frameworks to help us with this. Libraries like Redux, MobX and Vuex make managing cross-component state almost trivial. This is great for an application’s resilience and it works really well with a state-first, reactive framework such as React or Vue.

How do these libraries work though? What would it take to write one ourselves? Turns out, it’s pretty straightforward and there’s an opportunity to learn some really common patterns and also learn about some useful modern APIs that are available to us.

Before we get started, it’s recommended that you have an intermediary knowledge of JavaScript. You should know about data types and ideally, you should have a grasp of some more modern ES6+ JavaScript features. If not, we’ve got your back. It’s also worth noting that I’m not saying that you should replace Redux or MobX with this. We’re working on a little project to skill-up together and, hey, it could definitely power a small application if you were keeping an eye on the size of your JavaScript payload.

Getting started

Before we dive into code, take a look at what we’re building. It’s a “done list" that adds up the things you’ve achieved today. It’ll update various elements of the UI like magic — all with no framework dependencies. That’s not the real magic though. Behind the scenes, we’ve got a little state system that’s sitting, waiting for instructions and maintaining a single source of truth in a predictable fashion.

View Demo

View Repo

Pretty cool, right? Let’s do some admin first. I’ve put together a bit of a boilerplate so we can keep this tutorial snappy. The first thing you need to do is either clone it from GitHub, or download a ZIP archive and expand it.

Now that you’ve got that going, you’re going to need to run it in a local web server. I like to use a package called http-server for these sort of things, but you can use whatever you want. When you've got it running locally, you should see something that looks like this:

The initial state of our boilerplate. Setting up our structure

Open the root folder in your favorite text editor. This time, for me, the root folder is:

~/Documents/Projects/vanilla-js-state-management-boilerplate/

You should see a structure that looks a bit like this:

/src ??? .eslintrc ??? .gitignore ??? LICENSE ??? README.md Pub/Sub

Next, open up the src folder and then open up the js folder that lives in there. Make a new folder called lib. Inside that, make a new file called pubsub.js.

The structure of your js directory should look like this:

/js ??? lib ??? pubsub.js

Open up pubsub.js because we’re going to make a little Pub/Sub pattern, which is short for “Publish/Subscribe." We’re creating the functionality that allows other parts of our application to subscribe to named events. Another part of the application can then publish those events, often with some sort of relevant payload.

Pub/Sub is sometimes hard to grasp, so how about an analogy? Imagine you work in a restaurant and your customers have a starter and a main course. If you’ve ever worked in a kitchen, you’ll know that when the server clears the starters, they let the chefs know which table’s starters are cleared. This is a cue to start on the main courses for that table. In a big kitchen, there are a few chefs who will probably be on different dishes. They’re all subscribed to the cue from the server that the customers have finished their starters, so they know to do their function, which is to prepare the main course. So, you’ve got multiple chefs waiting on the same cue (named event) to do different functions (callback) to each other.

Hopefully thinking of it like that helps it make sense. Let’s move on!

The PubSub pattern loops through all of the subscriptions and fires their callbacks with that payload. It’s a great way of creating a pretty elegant reactive flow for your app and we can do it with only a few lines of code.

Add the following to pubsub.js:

export default class PubSub { constructor() { this.events = {}; } }

What we’ve got there is a fresh new class and we’re setting this.events as a blank object by default. The this.events object will hold our named events.

After the constructor's closing bracket, add the following:

subscribe(event, callback) { let self = this; if(!self.events.hasOwnProperty(event)) { self.events[event] = []; } return self.events[event].push(callback); }

This is our subscribe method. You pass a string event, which is the event’s unique name and a callback function. If there’s not already a matching event in our events collection, we create it with a blank array so we don’t have to type check it later. Then, we push the callback into that collection. If it already existed, this is all the method would do. We return the length of the events collection, because it might be handy for someone to know how many events exist.

Now that we’ve got our subscribe method, guess what comes next? You know it: the publish method. Add the following after your subscribe method:

publish(event, data = {}) { let self = this; if(!self.events.hasOwnProperty(event)) { return []; } return self.events[event].map(callback => callback(data)); }

This method first checks to see if the passed event exists in our collection. If not, we return an empty array. No dramas. If there is an event, we loop through each stored callback and pass the data into it. If there are no callbacks (which shouldn’t ever be the case), it’s all good, because we created that event with an empty array in the subscribe method.

That’s it for PubSub. Let’s move on to the next part!

The core Store object

Now that we’ve got our Pub/Sub module, we’ve got our only dependency for the meat‘n’taters of this little application: the Store. We’ll go ahead and start fleshing that out now.

Let’s first outline what this does.

The Store is our central object. Each time you see @import store from '../lib/store.js, you'll be pulling in the object that we're going to write. It'll contain a state object that, in turn, contains our application state, a commit method that will call our >mutations, and lastly, a dispatch function that will call our actions. Amongst this and core to the Store object, there will be a Proxy-based system that will monitor and broadcast state changes with our PubSub module.

Start off by creating a new directory in your js directory called store. In there, create a new file called store.js. Your js directory should now look like this:

/js ??? lib ??? pubsub.js ???store ??? store.js

Open up store.js and import our Pub/Sub module. To do that, add the following right at the top of the file:

import PubSub from '../lib/pubsub.js';

For those who work with ES6 regularly, this will be very recognizable. Running this sort of code without a bundler will probably be less recognizable though. There's a heck of a lot of support already for this approach, too!

Next, let's start building out our object. Straight after the import, add the following to store.js:

export default class Store { constructor(params) { let self = this; } }

This is all pretty self-explanatory, so let's add the next bit. We're going to add default objects for state, actions, and mutations. We're also adding a status element that we'll use to determine what the object is doing at any given time. This goes right after let self = this;:

self.actions = {}; self.mutations = {}; self.state = {}; self.status = 'resting';

Straight after that, we'll create a new PubSub instance that will be attached the Store as an events element:

self.events = new PubSub();

Next, we're going to search the passed params object to see if any actions or mutations were passed in. When the Store object is instantiated, we can pass in an object of data. Included in that can be a collection of actions and mutations that control the flow of data in our store. The following code comes next right after the last line that you added:

if(params.hasOwnProperty('actions')) { self.actions = params.actions; } if(params.hasOwnProperty('mutations')) { self.mutations = params.mutations; }

That's all of our defaults set and nearly all of our potential params set. Let's take a look at how our Store object keeps track of all of the changes. We're going to use a Proxy to do this. What the Proxy does is essentially work on behalf of our state object. If we add a get trap, we can monitor every time that the object is asked for data. Similarly with a set trap, we can keep an eye on changes that are made to the object. This is the main part we're interested in today. Add the following straight after the last lines that you added and we'll discuss what it's doing:

self.state = new Proxy((params.state || {}), { set: function(state, key, value) { state[key] = value; console.log(`stateChange: ${key}: ${value}`); self.events.publish('stateChange', self.state); if(self.status !== 'mutation') { console.warn(`You should use a mutation to set ${key}`); } self.status = 'resting'; return true; } });

What's happening here is we're trapping the state object set operations. That means that when a mutation runs something like state.name = 'Foo' , this trap catches it before it can be set and provides us an opportunity to work with the change or even reject it completely. In our context though, we're setting the change and then logging it to the console. We're then publishing a stateChange event with our PubSub module. Anything subscribed to that event's callback will be called. Lastly, we're checking the status of Store. If it's not currently running a mutation, it probably means that the state was updated manually. We add a little warning in the console for that to give the developer a little telling off.

There's a lot going on there, but I hope you're starting to see how this is all coming together and importantly, how we're able to maintain state centrally, thanks to Proxy and Pub/Sub.

Dispatch and commit

Now that we've added our core elements of the Store, let's add two methods. One that will call our actions named dispatch and another that will call our mutations called commit. Let's start with dispatch by adding this method after your constructor in store.js:

dispatch(actionKey, payload) { let self = this; if(typeof self.actions[actionKey] !== 'function') { console.error(`Action "${actionKey} doesn't exist.`); return false; } console.groupCollapsed(`ACTION: ${actionKey}`); self.status = 'action'; self.actions[actionKey](self, payload); console.groupEnd(); return true; }

The process here is: look for an action and, if it exists, set a status and call the action while creating a logging group that keeps all of our logs nice and neat. Anything that is logged (like a mutation or Proxy log) will be kept in the group that we define. If no action is set, it'll log an error and bail. That was pretty straightforward, and the commit method is even more straightforward.

Add this after your dispatch method:

commit(mutationKey, payload) { let self = this; if(typeof self.mutations[mutationKey] !== 'function') { console.log(`Mutation "${mutationKey}" doesn't exist`); return false; } self.status = 'mutation'; let newState = self.mutations[mutationKey](self.state, payload); self.state = Object.assign(self.state, newState); return true; }

This method is pretty similar, but let's run through the process anyway. If the mutation can be found, we run it and get our new state from its return value. We then take that new state and merge it with our existing state to create an up-to-date version of our state.

With those methods added, our Store object is pretty much complete. You could actually modular-ize this application now if you wanted because we've added most of the bits that we need. You could also add some tests to check that everything run as expected. But I'm not going to leave you hanging like that. Let's make it all actually do what we set out to do and continue with our little app!

Creating a base component

To communicate with our store, we've got three main areas that update independently based on what's stored in it. We're going to make a list of submitted items, a visual count of those items, and another one that's visually hidden with more accurate information for screen readers. These all do different things, but they would all benefit from something shared to control their local state. We're going to make a base component class!

First up, let's create a file. In the lib directory, go ahead and create a file called component.js. The path for me is:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/lib/component.js

Once that file is created, open it and add the following:

import Store from '../store/store.js'; export default class Component { constructor(props = {}) { let self = this; this.render = this.render || function() {}; if(props.store instanceof Store) { props.store.events.subscribe('stateChange', () => self.render()); } if(props.hasOwnProperty('element')) { this.element = props.element; } } }

Let's talk through this chunk of code. First up, we're importing the Store class. This isn't because we want an instance of it, but more for checking one of our properties in the constructor. Speaking of which, in the constructor we're looking to see if we've got a render method. If this Component class is the parent of another class, then that will have likely set its own method for render. If there is no method set, we create an empty method that will prevent things from breaking.

After this, we do the check against the Store class like I mentioned above. We do this to make sure that the store prop is a Store class instance so we can confidently use its methods and properties. Speaking of which, we're subscribing to the global stateChange event so our object can react. This is calling the render function each time the state changes.

That's all we need to write for that class. It'll be used as a parent class that other components classes will extend. Let's crack on with those!

Creating our components

Like I said earlier, we've got three components to make and their all going to extend the base Component class. Let's start off with the biggest one: the list of items!

In your js directory, create a new folder called components and in there create a new file called list.js. For me the path is:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/component/list.js

Open up that file and paste this whole chunk of code in there:

import Component from '../lib/component.js'; import store from '../store/index.js'; export default class List extends Component { constructor() { super({ store, element: document.querySelector('.js-items') }); } render() { let self = this; if(store.state.items.length === 0) { self.element.innerHTML = `<p class="no-items">You've done nothing yet &#x1f622;</p>`; return; } self.element.innerHTML = ` <ul class="app__items"> ${store.state.items.map(item => { return ` <li>${item}<button aria-label="Delete this item">×</button></li> ` }).join('')} </ul> `; self.element.querySelectorAll('button').forEach((button, index) => { button.addEventListener('click', () => { store.dispatch('clearItem', { index }); }); }); } };

I hope that code is pretty self-explanatory after what we've learned earlier in this tutorial, but let's skim through it anyway. We start off by passing our Store instance up to the Component parent class that we are extending. This is the Component class that we've just written.

After that, we declare our render method that gets called each time the stateChange Pub/Sub event happens. In this render method we put out either a list of items, or a little notice if there are no items. You'll also notice that each button has an event attached to it and they dispatch and action within our store. This action doesn't exist yet, but we'll get to it soon.

Next up, create two more files. These are two new components, but they're tiny — so we're just going to paste some code in them and move on.

First, create count.js in your component directory and paste the following in it:

import Component from '../lib/component.js'; import store from '../store/index.js'; export default class Count extends Component { constructor() { super({ store, element: document.querySelector('.js-count') }); } render() { let suffix = store.state.items.length !== 1 ? 's' : ''; let emoji = store.state.items.length > 0 ? '&#x1f64c;' : '&#x1f622;'; this.element.innerHTML = ` <small>You've done</small> ${store.state.items.length} <small>thing${suffix} today ${emoji}</small> `; } }

Looks pretty similar to list, huh? There's nothing in here that we haven't already covered, so let's add another file. In the same components directory add a status.js file and paste the following in it:

import Component from '../lib/component.js'; import store from '../store/index.js'; export default class Status extends Component { constructor() { super({ store, element: document.querySelector('.js-status') }); } render() { let self = this; let suffix = store.state.items.length !== 1 ? 's' : ''; self.element.innerHTML = `${store.state.items.length} item${suffix}`; } }

Again, we've covered everything in there, but you can see how handy it is having a base Component to work with, right? That's one of the many benefits of Object-orientated Programming, which is what most of this tutorial is based on.

Finally, let's check that your js directory is looking right. This is the structure of where we're currently at:

/src ??? js ? ??? components ? ? ??? count.js ? ? ??? list.js ? ? ??? status.js ? ???lib ? ? ???component.js ? ? ???pubsub.js ?????? store ???store.js ???main.js Let's wire it up

Now that we've got our front-end components and our main Store, all we've got to do is wire it all up.

We've got our store system and the components to render and interact with its data. Let's now wrap up by hooking up the two separate ends of the app and make the whole thing work together. We’ll need to add an initial state, some actions and some mutations. In your store directory, add a new file called state.js. For me it's like this:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/store/state.js

Open up that file and add the following:

export default { items: [ 'I made this', 'Another thing' ] };

This is pretty self-explanatory. We're adding a default set of items so that on first-load, our little app will be fully interactive. Let's move on to some actions. In your store directory, create a new file called actions.js and add the following to it:

export default { addItem(context, payload) { context.commit('addItem', payload); }, clearItem(context, payload) { context.commit('clearItem', payload); } };

The actions in this app are pretty minimal. Essentially, each action is passing a payload to a mutation, which in turn, commits the data to store. The context, as we learned earlier, is the instance of the Store class and the payload is passed in by whatever dispatches the action. Speaking of mutations, let's add some. In this same directory add a new file called mutations.js. Open it up and add the following:

export default { addItem(state, payload) { state.items.push(payload); return state; }, clearItem(state, payload) { state.items.splice(payload.index, 1); return state; } };

Like the actions, these mutations are minimal. In my opinion, your mutations should always be simple because they have one job: mutate the store's state. As a result, these examples are as complex as they should ever be. Any proper logic should happen in your actions. As you can see for this system, we return the new version of the state so that the Store`'s <code>commit method can do its magic and update everything. With that, the main elements of the store system are in place. Let's glue them together with an index file.

In the same directory, create a new file called index.js. Open it up and add the following:

import actions from './actions.js'; import mutations from './mutations.js'; import state from './state.js'; import Store from './store.js'; export default new Store({ actions, mutations, state });

All this file is doing is importing all of our store pieces and glueing them all together as one succinct Store instance. Job done!

The final piece of the puzzle

The last thing we need to put together is the main.js file that we included in our index.html page waaaay up at the start of this tutorial. Once we get this sorted, we'll be able to fire up our browsers and enjoy our hard work! Create a new file called main.js at the root of your js directory. This is how it looks for me:

~/Documents/Projects/vanilla-js-state-management-boilerplate/src/js/main.js

Open it up and add the following:

import store from './store/index.js'; import Count from './components/count.js'; import List from './components/list.js'; import Status from './components/status.js'; const formElement = document.querySelector('.js-form'); const inputElement = document.querySelector('#new-item-field');

So far, all we're doing is pulling in dependencies that we need. We've got our Store, our front-end components and a couple of DOM elements to work with. Let's add this next bit to make the form interactive, straight under that code:

formElement.addEventListener('submit', evt => { evt.preventDefault(); let value = inputElement.value.trim(); if(value.length) { store.dispatch('addItem', value); inputElement.value = ''; inputElement.focus(); } });

What we're doing here is adding an event listener to the form and preventing it from submitting. We then grab the value of the textbox and trim any whitespace off it. We do this because we want to check if there's actually any content to pass to the store next. Finally, if there's content, we dispatch our addItem action with that content and let our shiny new store deal with it for us.

Let's add some more code to main.js. Under the event listener, add the following:

const countInstance = new Count(); const listInstance = new List(); const statusInstance = new Status(); countInstance.render(); listInstance.render(); statusInstance.render();

All we're doing here is creating new instances of our components and calling each of their render methods so that we get our initial state on the page.

With that final addition, we are done!

Open up your browser, refresh and bask in the glory of your new state managed app. Go ahead and add something like "Finished this awesome tutorial" in there. Pretty neat, huh?

Next steps

There's a lot of stuff you could do with this little system that we've put together. Here are some ideas for taking it further on your own:

  • You could implement some local storage to maintain state, even when you reload
  • You could pull out the front-end of this and have a little state system for your projects
  • You could continue to develop the front-end of this app and make it look awesome. (I'd be really interested to see your work, so please share!)
  • You could work with some remote data and maybe even an API
  • You could take what you've learned about Proxy and the Pub/Sub pattern and develop those transferable skills further
Wrapping up

Thanks for learning about how these state systems work with me. The big, popular ones are much more complex and smarter that what we've done — but it's still useful to get an idea of how these systems work and unravel the mystery behind them. It's also useful to learn how powerful JavaScript can be with no frameworks whatsoever.

If you want a finished version of this little system, check out this GitHub repository. You can also see a demo here.

If you develop on this further, I'd love to see it, so hit me up on Twitter or post in the comments below if you do!

The post Build a state management system with vanilla JavaScript appeared first on CSS-Tricks.

Did you know that style and script tags can be set to display: block?

Css Tricks - Tue, 07/24/2018 - 12:27pm

The other night, Amit Patel mentioned that you can set script tags in HTML to display: block with CSS and then edit that code inline with the contentEditable attribute. This means that you can then see it all update live in the browser as you type. Shortly after, Marius Gundersen replied that you can do this with the style tag as well.

All of this is such a weird concept to me that I just had to make a demo to see if it worked:

tags" class="codepen">See the Pen contentEditable <style&rt; tags by Robin Rendle (@robinrendle) on CodePen.

And it does, as strange as that might be! All you need to do is add the contentEditable attribute to the style tag and make sure it’s set to display: block like so:

<p>content goes here</p> <style contenteditable> p { color: black; } </style> style { display: block; }

Why would we want to do this? Well, I’m not entirely sure. But it is certainly a neat demo. This also reminds me of the ever-so bizarre and brilliant demo Jake Albaugh made a while back, which just happens to be one of my favorite pens of all time:

See the Pen pen#PwLXXP by Jake Albaugh (@jakealbaugh) on CodePen.

The post Did you know that style and script tags can be set to display: block? appeared first on CSS-Tricks.

A Brief Introduction To Interaction Design

Usability Geek - Tue, 07/24/2018 - 9:27am
Most companies understand why they need a strong web presence, but they often leave the users out of the process. In a competitive digital landscape, businesses must do all they can do to assure a...
Categories: Web Standards

A Brief Introduction To Interaction Design

Usability Geek - Tue, 07/24/2018 - 9:27am
Most companies understand why they need a strong web presence, but they often leave the users out of the process. In a competitive digital landscape, businesses must do all they can do to assure a...
Categories: Web Standards

Finite State Machines with React

Css Tricks - Tue, 07/24/2018 - 4:06am

As JavaScript applications on the web have grown more complex, so too has the complexity of dealing with state in those applications — state being the aggregate of all the data that an application needs to perform its function. Over the last several years, there has been a ton of great innovation in the realm of state management through tools like Redux, MobX, and Vuex. Something that hasn’t gotten quite as much attention, though, is state design.

What in the heck do I mean by state design?

Let’s set the scene a little bit. In the past, when building an application that needs to fetch some data from a backend service and display it to the user, I’ve designed my state to use boolean flags for various things like isLoading, isSuccess, isError, and so on down the line. As this number of boolean flags grows, though, the number of possible states that my application can have grows exponentially with it — significantly increasing the likelihood of a user encountering an unintentional or error state.

To solve this issue, I’ve spent the last several months exploring the use of finite state machines as a way to better design the state of my applications.

Finite state machines are a mathematical model of computation, initially developed in the early 1940s, that have been used for decades to build both hardware and software for a wide array of technologies.

A finite state machine can be defined as any abstract machine that exists in exactly one of a finite number of states at a given time. In more practical terms, though, a state machine is characterized by a list of states with each state defining a finite, deterministic set of states that can be transitioned to by a given action.

Due to this finite and deterministic nature, we can use state diagrams to visualize our application — before or after it’s been built.

For example, if we wanted to visualize an authentication workflow, we could have three overarching states that our application could be in for a user: logged in, logged out, or loading.

A state diagram showing an application going from logged out, to loading, to logged in.

State machines, owing to their predictability, are especially popular in applications where reliability is critical — such as aviation software, manufacturing, and even the NASA Space Launch System. They’ve been a mainstay in the game development community for decades, as well.

In this article, we’ll tackle building something that most applications on the web use: authentication. We’ll use the state diagram above to guide us.

Before we get started, though, let’s familiarize ourselves with some of the libraries and APIs we’ll be using to build this application.

React Context API

React 16.3 introduced a new, stable version of the Context API. If you’ve worked much with React in the past, you may be familiar with how data is passed from parent to child through props. When you have certain data that is needed by a variety of components, you can end up doing what’s known as prop drilling — passing data through multiple levels of the component tree to get the data to a component that needs it.

Context helps alleviate the pain of prop drilling by providing a way to share data between components without having to explicitly pass that data through the component tree, making it perfect for storing authentication data.

When we create context, we get a Provider and Consumer pair. The provider will act as the “smart," stateful component that contains our state machine definition, and maintains a record of the current state of our application.

xstate

xstate is a JavaScript library for functional, stateless finite state machines and statecharts — it will provide us a nice, clean API for managing definitions and transitions through our states.

A stateless finite state machine library might sound a bit strange, but essentially what it means is that xstate only cares about the state and transition that you pass it — meaning it’s up to your application to keep track of its own current state.

xstate has a lot of features worth mentioning that we won’t cover much in this article (since we’ll only begin to scratch the surface on statecharts): hierarchical machines, parallel machines, history states, and guards, just to name a few.

The approach

So, now that we’ve had a little bit of an introduction to both Context and xstate, let’s talk about the approach we’ll be taking.

We’ll start by defining the context for our application, then creating a stateful <App /> component (our provider) that will contain our authentication state machine, along with information about the current user and a method for the user to logout.

To set the stage a bit, let’s take a quick look at a CodePen demo of what we’ll be building.

See the Pen Authentication state machine example by Jon Bellah (@jonbellah) on CodePen.

So, without further ado, let’s dig into some code!

Defining our context

The first thing we need to do is define our application context and set it up with some default values. Default values in context are helpful for allowing us to test components in isolation, since the default values are only used if there is no matching provider.

For our application, we’re going to set up a few defaults: authState which will be the authentication state of the current user, an object called user which will contain data about our user if they’re authenticated, then a logout() method that can be called anywhere in the app if the user is authenticated.

const Auth = React.createContext({ authState: 'login', logout: () => {}, user: {}, }); Defining our machine

When we think about how authentication behaves in an application, in its simplest form, there are three primary states: logged out, logged in, and loading. These are the three states we diagramed earlier.

Looking back at that state diagram, our machine consists of those same three states: logged out, logged in, and loading. We also have four different action types that can be fired: SUBMIT, SUCCESS, FAIL, and LOGOUT.

We can model that behavior in code like so:

const appMachine = Machine({ initial: 'loggedOut', states: { loggedOut: { onEntry: ['error'], on: { SUBMIT: 'loading', }, }, loading: { on: { SUCCESS: 'loggedIn', FAIL: 'loggedOut', }, }, loggedIn: { onEntry: ['setUser'], onExit: ['unsetUser'], on: { LOGOUT: 'loggedOut', }, }, }, });

So, we just expressed the diagram from earlier in code, but are you ready for me to let you in on a little secret? That diagram was generated from this code using David Khourshid’s xviz library — which can be used to visually explore the actual code that powers your state machines.

If you’re interested in diving deeper into complex user interfaces using finite state machines, David Khourshid has a related article here on CSS-Tricks worth checking out.

This can be an incredibly powerful tool when trying to debug problematic states in your application.

Referring back to the code above now, we define our initial application state — which we’re calling loggedOut since we’ll want to show the login screen on an initial visit.

Note that in a typical application, you’d probably want to start from the loading state and determine if the user was previously authenticated… but since we’re faking the login process, we’re starting from the logged out state.

In the states object, we define each of our states along with the corresponding actions and transitions for each of those states. Then we pass all that as an object to the Machine() function, which is imported from xstate.

Along with our loggedOut and loggedIn states, we’ve defined some actions that we want to fire when our application enters or exits those states. We’ll look at what those actions do in a bit.

This is our state machine.

To break things down one more time, let’s look at the loggedOut: { on: { SUBMIT: 'loading'} } line . This means that if our application is in the loggedOut state and we call our transition function with an action of SUBMIT, our application will always transition from the loggedOut state to the loading state. We can make that transition by calling appMachine.transition('loggedOut', 'SUBMIT').

From there, the loading state will either move the user along as an authenticated user or send them back to the login screen and display an error message.

Creating our context provider

The context provider will be the component that sits at the top level of our application and houses all the data related to an authenticated — or unauthenticated — user.

Working in the same file as our state machine definition, let’s create an <App /> component and set it up with everything we’ll need. Don’t worry, we’ll cover what each method does in just a moment.

class App extends React.Component { constructor(props) { super(props); this.state = { authState: appMachine.initialState.value, error: '', logout: e => this.logout(e), user: {}, }; } transition(event) { const nextAuthState = appMachine.transition(this.state.authState, event.type); const nextState = nextAuthState.actions.reduce( (state, action) => this.command(action, event) || state, undefined, ); this.setState({ authState: nextAuthState.value, ...nextState, }); } command(action, event) { switch (action) { case 'setUser': if (event.username) { return { user: { name: event.username } }; } break; case 'unsetUser': return { user: {}, }; case 'error': if (event.error) { return { error: event.error, }; } break; default: break; } } logout(e) { e.preventDefault(); this.transition({ type: 'LOGOUT' }); } render() { return ( <Auth.Provider value={this.state}> <div className="w5"> <div className="mb2">{this.state.error}</div> {this.state.authState === 'loggedIn' ? ( <Dashboard /> ) : ( <Login transition={event => this.transition(event)} /> )} </div> </Auth.Provider> ); } }

Whew, that was a lot of code! Let’s break it down into manageable chunks by taking a look at each method of this class individually.

In the constructor(), we’re setting our component state to the initial state of our appMachine, as well as setting our logout function in state, so that it can be passed through our application context to any consumer that needs it.

In the transition() method, we’re doing a few important things. First, we’re passing our current application state and the event type or action to xstate, so we can determine our next state. Then, in nextState, we take any actions associated with that next state (which will be one of our onEntry or onExit actions) and run them through the command() method — then we take all of the results and set our new application state.

In the command() method, we have a switch statement that returns an object — depending on the action type — which we use to pass data into our application state. This way, once a user has authenticated, we can set relevant details about that user — username, email, id, etc. — into our context, making it available to any of our consumer components.

Finally, in our render() method, we’re actually defining our provider component and then passing all of our current state through the value props, which makes the state available to all of the components beneath it in the component tree. Then, depending on the state of our application, we’re rendering either the dashboard or the login form for the user.

In this case, we have a pretty flat component tree beneath our provider (Auth.Provider), but remember that context allows that value to be available to any component beneath our provider in the component tree, regardless of depth. So, for example, if we have a component nested three or four levels down and we want to display the current user name, we can just grab that out of context, rather than drilling it all the way down to that one component.

Creating context consumers

Now, let’s create some components that consume our application context. From these components, we can do all sorts of things.

We can start by building a login component for our application.

class Login extends Component { constructor(props) { super(props); this.state = { yourName: '', } this.handleInput = this.handleInput.bind(this); } handleInput(e) { this.setState({ yourName: e.target.value, }); } login(e) { e.preventDefault(); this.props.transition({ type: 'SUBMIT' }); setTimeout(() => { if (this.state.yourName) { return this.props.transition({ type: 'SUCCESS', username: this.state.yourName, }, () => { this.setState({ username: '' }); }); } return this.props.transition({ type: 'FAIL', error: 'Uh oh, you must enter your name!', }); }, 2000); } render() { return ( <Auth.Consumer> {({ authState }) => ( <form onSubmit={e => this.login(e)}> <label htmlFor="yourName"> <span>Your name</span> <input id="yourName" name="yourName" type="text" value={this.state.yourName} onChange={this.handleInput} /> </label> <input type="submit" value={authState === 'loading' ? 'Logging in...' : 'Login' } disabled={authState === 'loading' ? true : false} /> </form> )} </Auth.Consumer> ); } }

Oh my! That was another big chunk of code, so let’s walk through each method again.

In the constructor(), we’re declaring our default state and binding the handleInput() method so that it references the proper this internally.

In handleInput(), we’re taking the value of our form field from our render() method and setting that value in state — this is referred to as a controlled form.

The login() method is where you would normally place your authentication logic. In the case of this app, we’re just faking a delay with setTimeout() and either authenticating the user — if they’ve provided a name — or returning an error if the field was left empty. Note that the transition() function that it calls is actually the one we defined in our <App /> component, which has been passed down via props.

Finally, our render() method displays our login form, but notice that the <Login /> component is also a context consumer. We’re using the authState context to determine whether or not to show our login button in a disabled, loading state.

Using context from deep in the component tree

Now that we’ve handled the creation of our state machine and a way for users to login to our application, we can now rely on having information about that user within any component nested under our <Dashboard /> component — since it will only ever be rendered if the user is logged in.

So let’s create a stateless component that grabs the username of the current authenticated user and displays a welcome message. Since we’re passing the logout() method to all of our consumers, we can also give the user the option of logging out from anywhere in the component tree.

const Dashboard = () => ( <Auth.Consumer> {({ user, logout }) => ( <div> <div>Hello {user.name}</div> <button onClick={e => logout(e)}> Logout </button> </div> )} </Auth.Consumer> ); Building larger applications with statecharts

Using finite state machines with React doesn’t have to be limited to authentication, nor does it have to be limited to the context API.

Using statecharts, you can have hierarchical machines and/or parallel machines — meaning individual React components can have their own internal state machine, but still be connected to the overall state of your application.

In this article, we've primarily focused on using xstate directly with the native Context API; in larger applications, I highly recommend looking at react-automata, which provides a thin layer of abstraction over the top of xstate. react-automata has the added benefit of being able to automagically generate Jest tests for your components.

State machines and state management tools are not mutually exclusive

It’s easy to get confused by thinking you must either use, say, xstate or Redux; but it’s important to note that state machines are more of an implementation concept, concerned with how you design your state — not necessarily how you manage it.

In fact, state machines can be used with just about any un-opinionated state management tool. I encourage you to explore various approaches to determine what works best for you, your team, and your application(s).

In conclusion

These concepts can be extended to the real world without having to refactor your entire application. State machines are an excellent refactor target — meaning, next time you’re working on a component that is littered with boolean flags like isFetching and isError, consider refactoring that component to use a state machine.

As a front-end developer, I’ve found that I’m often fixing one of two categories of bugs: display-related issues or unexpected application states.

State machines make the second category virtually disappear.

If you’re interested in diving deeper into state machines, I’ve spent the last several months working on a course on finite state machines — if you sign up for the email list, you’ll receive a discount code when the course launches in August.

The post Finite State Machines with React appeared first on CSS-Tricks.

Developer Roadmaps

Css Tricks - Mon, 07/23/2018 - 11:12am

The path to becoming a front-end developer, as looked back upon by anyone who self-identifies that way, is likely a very windy one full of thorn bushes and band websites. Still, documenting a path, even if it's straighter and far cleaner than reality, is an interesting exercise and might just be valuable. Three different writer/developers have taken a crack at it this year and their results have been extraordinarily popular. Let's take a look.

These might help inform web education curriculum as well.

Kamran Ahmed's Modern Front-End Developer in 2018

From here.

Adam Go??b's React Developer Roadmap

From here.

Adnan Ahmed's Modern Back-End Developer in 2018

From here.

Flavio Copes's Roadmap to Become a Vue.js Developer 2018

From here.

My own path is something I documented in a different format, but is no less complex. It'd be interesting to see if we can get a collection of these going based on your own experiences.

The post Developer Roadmaps appeared first on CSS-Tricks.

3 Easy Ways To Gamify Your UX

Usability Geek - Mon, 07/23/2018 - 9:26am
According to reward system psychology, as we play games and are rewarded, our brains release dopamine. Thus, it makes sense that you like playing games – your brain likes it. As a result, we...
Categories: Web Standards

3 Easy Ways To Gamify Your UX

Usability Geek - Mon, 07/23/2018 - 9:26am
According to reward system psychology, as we play games and are rewarded, our brains release dopamine. Thus, it makes sense that you like playing games – your brain likes it. As a result, we...
Categories: Web Standards

View Source

Css Tricks - Mon, 07/23/2018 - 6:44am

I remember seeing this Tom Dale tweet a while back. It's literally about the browser's ability to look at the HTML of the document you're looking at as it first arrived. Now the tweet is stirring up a new round of conversation.

Jonathan Snook has kind of a baby bear take:

We have the ability to inspect the original HTML source along with its interpreted representation. We have the ability to inspect the source of JavaScript and CSS files mapped from its minified and optimized versions. We have the ability to inspect rendering pipelines. We have the ability to stop and step through JavaScript execution line by line.

The increasing complexity of tools doesn’t negate the need for those earlier, simpler tools, though.

The sites some build may be simple static sites, befitting of a simple View Source. The sites some build may be compiled and bundled and requiring tools that allow us to dig deeper. Just because you don’t need those tools doesn’t mean that somebody doesn’t need those tools.

And Chris Heilmann:

For a simple web site with everything in one document or a few linked scripts and stylesheets, that was enough.

I don’t think it is any longer though. Even navigating simple source code of a web site is much more fun in developer tools rather than a huge text block. We can right-click on an element these days and go directly to it. We see how the cascade works when looking at its CSS and we even can see attached events and hover states.

Sure, developer tools are harder to learn than looking at a document, but you also learn so much more from them. The beauty of view-source was that it came for free with a browser. This made it a tool of choice for anyone becoming a web developer. There was no need to download and learn an IDE - your development environment was the consumption environment.

Well, that’s exactly what developer tools are these days. They are free, they come with the browser, and they are not impossible to understand. If anything, I like the fact that they give you more insights into what the code does rather than what it is.

I'll take a hard-line stance, just for fun here: I literally don't care at all about View Source and wouldn't miss it if it was removed from browsers. I live in DevTools, and I'll bet you do too. It entirely supersedes View Source, as you can quite literally view source inside it if you'd like. But that's beside the point.

I don't want my source to be human-readable, not for protective reasons, but because I care about web performance more. I want my website to arrive at light speed on a tiny spec of magical network packet dust and blossom into a complete website. Or do whatever computer science deems is the absolute fastest way to send website data between computers. I'm much more worried about the state of web performance than I am about web education. But even if I was very worried about web education, I don't think it's the network's job to deliver teachability.

The post View Source appeared first on CSS-Tricks.

Adding Particle Effects to DOM Elements with Canvas

Css Tricks - Mon, 07/23/2018 - 3:56am

Let’s take a look at how to make web pages more visually capable by combining the freedom of <canvas> with HTML elements. Specifically, we will be creating a basic HTML-to-particle effect, but the same technique could be used for many kinds of effects.

Before we begin, feel free to grab the source code in the repo.

View Repo

Create the initial element

First, let’s create an HTML element to build on. I'm using a simple styled button, but it really could be any HTML element.

See the Pen DOM to Canvas #1 by Zach Saucier (@Zeaklous) on CodePen.

A modern browser like Chrome, Firefox, or Edge is required to view these demos.

But how can we get a canvas to "see" this element so that we can manipulate each pixel using canvas? In order to make that to happen, we will essentially need to take a snapshot of our HTML element — like a "print screen" but only for the particular element (the button) that we're looking to manipulate in canvas.

Create a canvas version of our element

Even though there's no native way for browsers to do this and allow us to manipulate it in JavaScript, there is a very handy library called html2canvas that can help us. All we have to do is load the library, then call html2canvas(element) and it will return a Promise along with a canvas version of our element! Crazy awesome.

See the Pen DOM to Canvas #2 by Zach Saucier (@Zeaklous) on CodePen.

Here we have an HTML version and a canvas version of our button next to each other. We can use the canvas version as our "screenshot" and as a source for information, such as the color of a pixel at a particular location.

Getting data from our canvas

To do that, let's create a new function to get the pixel information at a particular location. We also don't need to display the canvas that we'd get our color data from, because we want to show the original HTML element instead.

function getColorAtPoint(e) { // Get the coordinate of the click let x = e.offsetX; let y = e.offsetY; // Get the color data of the canvas version of our element at that location let rgbaColorArr = ctx.getImageData(x, y, 1, 1).data; // Do something with rgbaColorArr }

See the Pen DOM to Canvas #3 by Zach Saucier (@Zeaklous) on CodePen.

Now we need to create a canvas particle using that information.

Create a canvas for displaying particles

We don’t really have a canvas to put the particles on yet because we want to reserve the canvas that we got from html2canvas for accessing color information only. So let’s create another:

var particleCanvas, particleCtx; function createParticleCanvas() { // Create our canvas particleCanvas = document.createElement("canvas"); particleCtx = particleCanvas.getContext("2d"); // Size our canvas particleCanvas.width = window.innerWidth; particleCanvas.height = window.innerHeight; // Position out canvas particleCanvas.style.position = "absolute"; particleCanvas.style.top = "0"; particleCanvas.style.left = "0"; // Make sure it's on top of other elements particleCanvas.style.zIndex = "1001"; // Make sure other elements under it are clickable particleCanvas.style.pointerEvents = "none"; // Add our canvas to the page document.body.appendChild(particleCanvas); } Get coordinate data

We also need to continue to get the color data from our local coordinate — not only the top and left of our button, but also the position in global coordinates (in relation to the entire web page) in order to create the particle in the right place on the canvas.

We can do so using the following:

btn.addEventListener("click", e => { // Get our color data like before let localX = e.offsetX; let localY = e.offsetY; let rgbaColorArr = ctx.getImageData(localX, localY, 1, 1).data; // Get the button's positioning in terms of the window let bcr = btn.getBoundingClientRect(); let globalX = bcr.left + localX; let globalY = bcr.top + localY; // Create a particle using the color we obtained at the window location // that we calculated createParticleAtPoint(globalX, globalY, rgbaColorArr); }); Create a particle prototype

And let’s also create a basic particle that has a draw function using variables:

/* An "exploding" particle effect that uses circles */ var ExplodingParticle = function() { // Set how long we want our particle to animate for this.animationDuration = 1000; // in ms // Set the speed for our particle this.speed = { x: -5 + Math.random() * 10, y: -5 + Math.random() * 10 }; // Size our particle this.radius = 5 + Math.random() * 5; // Set a max time to live for our particle this.life = 30 + Math.random() * 10; this.remainingLife = this.life; // This function will be called by our animation logic later on this.draw = ctx => { let p = this; if(this.remainingLife > 0 && this.radius > 0) { // Draw a circle at the current location ctx.beginPath(); ctx.arc(p.startX, p.startY, p.radius, 0, Math.PI * 2); ctx.fillStyle = "rgba(" + this.rgbArray[0] + ',' + this.rgbArray[1] + ',' + this.rgbArray[2] + ", 1)"; ctx.fill(); // Update the particle's location and life p.remainingLife--; p.radius -= 0.25; p.startX += p.speed.x; p.startY += p.speed.y; } } } Create a particle factory

We also need a function to create these particles based on some coordinates and color information, making sure that we add them to the array of particles that get created:

var particles = []; function createParticleAtPoint(x, y, colorData) { let particle = new ExplodingParticle(); particle.rgbArray = colorData; particle.startX = x; particle.startY = y; particle.startTime = Date.now(); particles.push(particle); } Add animation logic

We also need a way to animate any particles that are created.

function update() { // Clear out the old particles if(typeof particleCtx !== "undefined") { particleCtx.clearRect(0, 0, window.innerWidth, window.innerHeight); } // Draw all of our particles in their new location for(let i = 0; i < particles.length; i++) { particles[i].draw(particleCtx); // Simple way to clean up if the last particle is done animating if(i === particles.length - 1) { let percent = (Date.now() - particles[i].startTime) / particles[i].animationDuration[i]; if(percent > 1) { particles = []; } } } // Animate performantly window.requestAnimationFrame(update); } window.requestAnimationFrame(update);

Putting those pieces together, we can now create particles based on our HTML element when we click it!

See the Pen DOM to Canvas #4 by Zach Saucier (@Zeaklous) on CodePen.

A particle fires out of the button each time it is clicked.

Neat!

If we want to “explode" the whole button on click instead of just one pixel, we only need to amend our click function:

let reductionFactor = 17; btn.addEventListener("click", e => { // Get the color data for our button let width = btn.offsetWidth; let height = btn.offsetHeight let colorData = ctx.getImageData(0, 0, width, height).data; // Keep track of how many times we've iterated (in order to reduce // the total number of particles create) let count = 0; // Go through every location of our button and create a particle for(let localX = 0; localX < width; localX++) { for(let localY = 0; localY < height; localY++) { if(count % reductionFactor === 0) { let index = (localY * width + localX) * 4; let rgbaColorArr = colorData.slice(index, index + 4); let bcr = btn.getBoundingClientRect(); let globalX = bcr.left + localX; let globalY = bcr.top + localY; createParticleAtPoint(globalX, globalY, rgbaColorArr); } count++; } } });

See the Pen DOM to Canvas #5 by Zach Saucier (@Zeaklous) on CodePen.

Now the button appears to explode into many tiny particles when clicked.

Hopefully, the web now feels less restrictive than it did at the start of this article now that we know we can use additions (like canvas) to exercise more creative freedom.

We can get even more creative by using edge detection to tell if our element is outside of the bounds of a container (i.e. hidden from view) and create particles when our element goes outside of those bounds.

A whole article could be written on this process because positioning of elements in a web browser is complex, but I’ve created a small plugin called Disintegrate that includes handling for this sort of thing.

Disintegrate: A plugin to create this effect for for you

Disintegrate is open source and handles a lot of the messiness that getting production-ready code for this technique requires. It also allows for multiple elements to apply this effect on the same page, specified containers to be used, a way to ignore specified colors, if needed, and events for the different important moments in the process.

View Repo

Using Disintegrate, we just have to declare data-dis-type="contained" on our button and it will make it so that when our element goes outside its container's bounds, particles will be created! See the demo for yourself.

Disintegrate’s contain effect on a draggable element.

A different type of effect we can make using Disintegrate is where the container is directly surrounding our element. This allows for self-contained particle animations like the button effect we made earlier. By animating the container and our main element itself, we can create particles in even more interesting ways.

A slide to unlock animation triggers exploding particles at the end.

However, this approach does have its limitations (and so does Disintegrate). For example, it will only work back to IE11 due to the lack of pointer-events support before that (provided Disintegrate is compiled to ES5). Disintegrate also doesn't support every DOM element we can imagine due to the limitations of html2canvas. The ones that I found most restricting are the incomplete CSS transform support and lack of clip-path support.

To install Disintegrate, you can use npm install disintegrate if you use npm. Or you can manually include html2canvas.js and disintegrate.js before calling disintegrate.init().

Disintegrate is very new and could use some improvements. If you'd like to contribute, both Disintegrate and html2canvas are open source and suggestions are welcome!

How do you think this functionality could be used in your projects? How do you see this approach extending what is possible on the web? Let me know in the comments.

The post Adding Particle Effects to DOM Elements with Canvas appeared first on CSS-Tricks.

What Can Bike Sharing Apps Teach Us About Mobile On-boarding Design?

LukeW - Sun, 07/22/2018 - 2:00pm

Given the proliferation of bike/scooter sharing services these days, I thought it would be interesting to compare the mobile app on-boarding experiences of the ones I could access. To do so, I went through the new customer flow for six of these services.

While the mobile on-boarding I experienced across these services looked really similar, the end result differed dramatically -from me abandoning the process to walking away a delighted customer. Understanding how product design impacted these outcomes is critical for anyone trying to grow a new mobile business.

Applying Design Patterns

My first encounter with bike sharing, appropriately, was in Amsterdam. I was outside the city center for a meeting and encountered a rack of Hello-Bikes. So why not bike back to my hotel in town? Here’s what happened when I tried.

Hello-Bike’s mobile on-boarding consists of several common patterns: a splash screen, a sign-up form, terms and conditions, and a tutorial. Though widely used, starting the design process off with these types of patterns often results in a flow that seems right in mock-ups or wireframes but fails to solve actual customer needs.

The designer thinks: “I know what an on-boarding flow is. It’s a splash screen, a sign-up screen and a tutorial people can swipe through.” The resulting customer experience in filling in form fields, scrolling through 17 screens of terms & conditions (yes, you are required to scroll through all of them), granting location permissions (because “background location-tracking is required”), and skipping through 6 tutorial screens featuring critical knowledge like “Welcome to Hello-Bike.”

After maneuvering through all this, I found out there were no docking stations in central Amsterdam because of government regulation. So I actually couldn’t use the Hello-Bike service to ride to my hotel. Starting the design process from the perspective of the customer would likely have revealed the importance of communicating these kinds of constraints up front. Starting by selecting design patterns would not.

Lessons Learned:
  • Set expectations appropriately, so potential customers don’t end a lengthy sign-up process in disappointment or frustration.
  • While convenient, design patterns are no substitute for understanding and designing with your customers & their goals top of mind.
Having Desktop Bias

While modern mobile devices have been around for over ten years, desktop devices have had at least 3x more time to influence and bias our approach to software design. That’s why it’s not surprising to see desktop design concepts permeate mobile apps. In the case of Jump’s mobile on-boarding, they are all over the place.

Following the obligatory splash screen, Jump animates through a series of safety tips calling out the unique features of electric bikes. Unfortunately, so many steps follow these tips that I can’t imagine anyone remembering them when they are finally allowed to ride one of Jump’s electric bikes.

Next up are a series of permission dialogs for access to Motion & Fitness and Location data. Both requests are accompanied by explanatory text that suggests Jump needs access to this information in order to “gather data about how electric bikes affect travel patterns.” Sounds like a good thing for Jump, but it’s not clear why customers should participate or even care.

This mindset permeates the rest of Jump’s on-boarding as well: choose one of our bike “networks”, select one of our plans, verify your phone number, pick a 7 character password with numbers and uppercase letters, agree to our terms and conditions, put money into one of our accounts, etc. After ten steps of doing things for Jump and seeing no progress toward actually riding a bike, I abandoned at the “Enter Credit Card” step.

Perhaps someone at Jump heard completion rates for forms go up when you place each question on a separate screen (I’ve seen no evidence of this), but the cumulative effect of going through a desktop-design influenced e-commerce checkout flow one step at a time on my phone was quite painful.

Lessons Learned:
  • Make sure your customers always feel like they are making progress toward their goals, not yours.
  • Desktop paradigms often aren’t a great fit for mobile. For instance, do you really need a checkout form? As we’ll see later, no.
Right Time, Right Place

After abandoning the bike-sharing process with both Hello-Bike and Jump, I had my first successful on-boarding with Spin. That’s not to say there wasn’t a lot of room for improvement. With mobile on-boarding it’s not just what we ask people to do it’s also when we ask them to do it. Spin starts off with a tutorial, which explains they are smart, I can park anywhere, and scanning a bike’s QR code will let me ride it.

Turns out that’s not entirely true as I needed to give them my email address, create a password, provide location permissions, and agree to three separate terms of service. It’s only after this gauntlet, that I’m actually able to scan the QR code on the bike in front of me. Why couldn’t we just have started the process there?

It is worth noting, however, that Spin provides much better explanations for its permission requests. When requesting location permissions, Hello-Bike told me: “background-location tracking is required” and Jump explained I could help them “gather data about how electric bikes affect travel patterns.” Spin, on the other hand, explained they use location to help me find pick-up and drop off points. They also explained they needed camera permissions so I can scan the QR code on a bike to unlock it.

After I did, my next step was to reload my Spin account, with the only reloading option being $5. This immediately felt odd as the bike ride itself was advertised as $1. So if I never rode another Spin bike again, they had 4 more dollars from me... hmmmm. On a positive note, Spin integrated with Apple Pay which meant I simply had to tap a button on the side of my phone to approve payment. No checkout forms, shopping carts, or credit card entry forms required. See? We can do things in a mobile-native vs. desktop way.

Following the payment process, I was greeted with a another tutorial (these things sure are popular huh? too bad most people skip through them). This time 4 screens told me about parking requirements. But wait… didn’t the first tutorial tell me I could park anywhere? Next Spin asked to send me notifications with no explanation as to why I should agree. So I didn’t.

Once I rode the bike and got to my destination, I received a ride summary that told me my ride was free. That’s much appreciated but it left me asking again… couldn’t we have started there?

Lessons Learned:
  • When you surface information to customers is critical. Spin could have told me my ride was free well before asking me to fill my account with a minimum of $5. And their Parking tutorial was probably more appropriate after my ride when parking my bike, not before it.
  • Get people to your core value as soon as possible, but not sooner. It took 7 steps before I was able to scan the bike in front of me and 9 more steps before I could actually ride it. Every step that keeps customers from experiencing what makes you great, leaves them wondering why you’re not.
Tricky, Tricky

By now, Ofo’s mobile on-boarding process will seem familiar: location and notification permission asks without any useful explanations, an up-front tutorial, a phone number verification flow, a camera permission ask, and more.

For many mobile apps, phone number verification can replace the need for more traditional desktop computer influenced sign-up process that require people to enter their first and last names, email addresses, passwords, and more into a series of form fields. When you’re on a phone, all you need to verify it’s you is your phone number.

With this simplified account creation process, Ofo could have had me on my way with a quick QR code scan. But instead I got a subscription service promotion that suggested I could try the service for free. After tapping the “Try it Free” button, however, I ended up on a Choose your Plan page. It was only when I used the small back arrows (tricky, tricky) that I made it back to the QR code unlock process which let me ride the Ofo bike in front of me with no charge.

Lessons Learned:
  • Mobile device capabilities allow us to rethink how people can accomplish tasks. For instance, instead of multiple step sign-up forms, a two step phone verification process can establish someone’s account much quicker by using what mobile devices do well.
  • While companies have revenue and growth needs, unclear flows and UI entrapments are not the way to build long-term customer loyalty and growth. You may trick some people into subscribing to your service but they won’t like you for it.
But Why?

Starting Bird’s mobile on-boarding gave me high hopes that I had finally found a streamlined customer-centric process that delivered on the promise of fast & easy last-mile transportation (or micro-mobility, if you must).

Things started out typically, a splash screen, an email form field, a location permission ask, but then moved right to scanning the QR code of the scooter in front of me and asking me to pay the $1 required to get started. Great, I thought… I’ll be riding in no time as I instantly made it through Apple Pay’s confirmation screen.

As a quick aside, integrating native payment platforms can really accelerate the payment process and increase conversion. Hotel Tonight saw a 26% increase in conversion with Apple Pay and Wish used A/B testing to uncover a 2X conversion increase when they added Apple Pay support. Turns out people do prefer to just look (Face ID) or tap (Touch ID) to pay for things on their phones instead of entering credit card or banking account details into mobile keyboards.

But back to Bird... I scanned the QR code and authorized Apple Pay. Time to ride right? Not quite. Next I was asked to scan the front of my drivers’ license with no explanation of why. Odd, but I assumed it was a legal/safety thing and despite having a lot of privacy reservations got through it. Or so I thought because after this I had to scan the back of my drivers’ license, scroll through all 15 screens of a rental agreement, and tick off 6 checkboxes saying I agreed to wear a helmet, not ride downhill, and was over 18 (can’t they get that from my driver’s license?).

Then it was back to scanning the QR code again, turning down notification permissions, and slogging through a 4 screen tutorial which ended with even more rules. The whole process left me feeling the legal department had taken over control of Bird’s first time customer experience: rental contracts, local rules, driver’s license verifications, etc. -really not in line with the company’s brand message of “enjoy the ride”. I left being intimated by it.

Lessons Learned:
  • Rules and regulations do exist but mobile on-boarding flows shouldn’t be driven by them. There’s effective ways to balance legal requirements and customer experience. Push hard to find them.
  • When asking for personal (especially highly personal) information, explain why. Even just a sentence about why I had to scan my driver’s license would have helped me immensely with Bird’s process.
Core Value, ASAP

By now, we’ve seen how very similar companies can end up with very different mobile on-boarding designs and results. So how can companies balance all the requirements and steps involved in bike-sharing and still deliver a great first-time experience? By always looking at things from the perspective of your customer. Which Lime, while not perfect, does.

Lime doesn’t bother with a splash screen showing you their logo as a first step. Instead they tell you upfront that they know why you’re here with a large headline stating: “Start Riding Now”. Awesome. That’s what I’ve been trying to do this whole time. On this same screen are two streamlined sign-up options: phone number verification (which makes use of native device capabilities) and Facebook -both aimed at getting you started right away.

Next, Lime takes the time to explain why they are asking for location permissions with the clearest copy we’ve seen in all these examples: “to find nearby bikes and scooters”. Sadly, they don’t apply this same level of clarification to the next permission ask for Notifications. But smartly, they use a double dialog solution and if you say no (which I did), they try again with more clarity.

It’s become almost standard practice to just ask for notification permissions up front in mobile apps because up to 40% of people will just give them to you. So many apps figure, why not ask? Lots of people will say no but we’ll get some people saying yes. Personally, I feel this is an opportunity to improve for Lime.

Ignoring the notifications prompt, the rest of Lime’s on-boarding process is fast and efficient: scan the QR code (once again with a clear explanation of why camera permissions are needed), authorize Apple Pay to pay for your ride. Lime doesn’t either bother to provide other payment options. They know the user experience and conversion benefits of Apple Pay and rely on it exclusively.

And… that’s it. I’m riding. No tutorial! Shocking I know, but they do offer one on the map screen if you’d like to learn more before riding. User choice, not company requirement.

In their mobile on-boarding, Lime deftly navigated a number of significant hurdles: account set-up/verification, location & camera permissions and payment -the minimum amount necessary to ride and nothing more. They did so by explaining how each of these steps got me closer to my goal of riding and worked hard to minimize their requirements, often relying on native mobile functionality to make things as fast and easy as possible.

Lessons Learned:
  • It’s not about you, it’s about your customer. Put your customer’s goals front and center in your mobile on-boarding process. It starts from the first screen (i.e. “Start Riding Now”)
  • Lean into mobile-native solutions: phone verification, integrated payments, and more.
More On On-boarding

For a deeper look into mobile on-boarding design, check out this 20 minute segment of my Mobile design and data presentation at Google Conversions this year: You can also read Casey Winter’s article about on-boarding, which does a great job outlining the concept of getting people to your company’s core value as fast as possible, but not faster.

Syndicate content
©2003 - Present Akamai Design & Development.