Let’s Build a JAMstack E-Commerce Store with Netlify Functions

A lot of people are confused about what JAMstack is. The acronym stands for JavaScript, APIs, and Markup, but truly, JAMstack doesn’t have to include all three. What defines JAMstack is that it’s served without web servers. If you consider the history of computing, this type of abstraction isn’t unnatural; rather it’s the inevitable progression this industry has been moving towards.

So, if JAMstack tends to be static by definition, it can’t have dynamic functionality, server-side events, or use a JavaScript framework, right? Thankfully, not so. In this tutorial, we’ll set up a JAMstack e-commerce app and add some serverless functionality with Netlify Functions (which abstract AWS Lambda, and are super dope in my opinion).

I’ll show more directly how the Nuxt/Vue part was set up in a follow-up post, but for now we’re going to focus on the Stripe serverless function. I’ll show you how I set this one up, and we’ll even talk about how to connect to other static site generators such as Gatsby.

This site and repo should get you started if you’d like to set something like this up yourself:

Scaffold our app

The very first step is to set up our app. This one is built with Nuxt to create a Vue app, but you can replace these commands with your tech stack of choice:

yarn create nuxt-app hub create git add -A
git commit -m “initial commit” git push -u origin master

I am using yarn, hub (which allows me to create repos from the command line) and Nuxt. You may need to install these tools locally or globally before proceeding.

With these few commands, following the prompts, we can set up an entirely new Nuxt project as well as the repo.

If we log into Netlify and authenticate, it will ask us to pick a repo:

choose a repo in netlify

I’ll use yarn generate to create the project. With that, I can add in the site settings for Nuxt in the dist directory and hit feploy! That’s all it takes to set up CI/CD and deploy the site! Now every time I push to the master branch, not only will I deploy, but I’ll be given a unique link for that particular deploy as well. So awesome.

A basic serverless function with Netlify

So here’s the exciting part, because the setup for this kind of functionality is so quick! If you’re unfamiliar with Serverless, you can think of it like the same JavaScript functions you know and love, but executed on the server. Serverless functions are event-driven logic and their pricing is extremely low (not just on Netlify, but industry-wide) and scales with your usage. And yes, we have to add the qualifier here: serverless still uses servers, but babysitting them is no longer your job. Let’s get started.

Our very basic function looks like this. I stored mine in a folder named functions, and just called it index.js. You can truly call the folder and function what you want.

// functions/index.js
exports.handler = async (event, context) => { return { statusCode: 200, body: JSON.stringify({ message: "Hi there Tacos", event }) }

We’ll also need to create a netlify.toml file at the root of the project and let it know which directory to find the function in, which in this case, is “functions.”

// netlify.toml
[build] functions = "functions"

If we push to master and go into the dashboard, you can see it pick up the function!

netlify function in the dashboard

If you look at the endpoint listed above it’s stored here:

Really, for any site you give it, the URL will follow this pattern:

When we hit that endpoint, it provides us with the message we passed in, as well as all the event data we logged as well:

the function event in the browser

I love how few steps that is! This small bit of code gives us infinite power and capabilities for rich, dynamic functionality on our sites.

Hook up Stripe

Pairing with Stripe is extremely fun because it’s easy to use, sophisticated, has great docs, and works well with serverless functions. I have other tutorials where I used Stripe because I enjoy using their service so much.

Here’s a bird’s eye view of the app we’ll be building:

First we’ll go to the Stripe dashboard and get our keys. For anyone totally scandalized right now, it’s OK, these are testing keys. You can use them, too, but you’ll learn more if you set them up on your own. (It’s two clicks and I promise it’s not hard to follow along from here.)

testing keys in the stripe dashboard

We’ll install a package called dotenv which will help us store our key and test it locally. Then, we’ll store our Stripe secret key to a Stripe variable. (You can call it anything, but here I’ve called it STRIPE_SECRET_KEY, and that’s pretty much industry standard.)

yarn add dotenv
require("dotenv").config() const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY)

In the Netlify dashboard, we’ll go to “Build & deploy,” then “Environment” to add in Environment variables, where the STRIPE_SECRET_KEY is key, and the value will be the key that starts with sk.

We’ll also add in some headers so we don’t run into CORS issues. We’ll use these headers throughout the function we’re going to build.

const headers = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "Content-Type"

So, now we’ll create the functionality for talking to Stripe. We’ll make sure we’ll handle the cases that it’s not the HTTP method we’re expecting, and also that we’re getting the information we expect.

You can already see here, what data we’re going to be needing to send to stripe by what we check for. We’ll need the token, the total amount, and an idempotency key.

If you’re unfamiliar with idempotency keys, they are unique values that are generated by a client and sent to an API along with a request in case the connection is disrupted. If the server receives a call that it realizes is a duplicate, it ignores the request and responds with a successful status code. Oh, and it’s an impossible word to pronounce.

exports.handler = async (event, context) => { if (!event.body || event.httpMethod !== "POST") { return { statusCode: 400, headers, body: JSON.stringify({ status: "invalid http method" }) } } const data = JSON.parse(event.body) if (!data.stripeToken || !data.stripeAmt || !data.stripeIdempotency) { console.error("Required information is missing.") return { statusCode: 400, headers, body: JSON.stringify({ status: "missing information" }) } }

Now, we’ll kick off the Stripe payment processing! We’ll create a Stripe customer using the email and token, do a little logging, and then create the Stripe charge. We’ll specify the currency, amount, email, customer ID, and give a description while we’re at it. Finally, we’ll provide the idempotency key (pronounced eye-dem-po-ten-see), and log that it was successful.

(While it’s not shown here, we’ll also do some error handling.)

// stripe payment processing begins here
try { await stripe.customers .create({ email: data.stripeEmail, source: data.stripeToken }) .then(customer => { console.log( `starting the charges, amt: ${data.stripeAmt}, email: ${data.stripeEmail}` ) return stripe.charges .create( { currency: "usd", amount: data.stripeAmt, receipt_email: data.stripeEmail, customer: customer.id, description: "Sample Charge" }, { idempotency_key: data.stripeIdempotency } ) .then(result => { console.log(`Charge created: ${result}`) }) })

Hook it up to Nuxt

If we look back at our application, you can see we have pages and components that live inside the pages. The Vuex store is like the brain of our application. It will hold the state of the app, and that’s what will communicate with Stripe. However, we still need to communicate with our user via the client. We’ll collect the credit card data in a component called AppCard.vue that will live on the cart page.

First, we’ll install a package called vue-stripe-elements-plus, that gives us some Stripe form elements that allow us to collect credit card data, and even sets us up with a pay method that allows us to create tokens for stripe payment processing. We’ll also add a library called uuid that will allow us to generate unique keys, which we’ll use for the idempotency key.

yarn add vue-stripe-elements-plus uuid

The default setup they give us to work with vue-stripe-elements-plus looks like this:


Please give us your payment details:


import { stripeKey, stripeOptions } from './stripeConfig.json'
import { Card, createToken } from 'vue-stripe-elements-plus' export default { data () { return { complete: false, stripeOptions: { // see https://stripe.com/docs/stripe.js#element-options for details } } }, components: { Card }, methods: { pay () { // createToken returns a Promise which resolves in a result object with // either a token or an error key. // See https://stripe.com/docs/api#tokens for the token object. // See https://stripe.com/docs/api#errors for the error object. // More general https://stripe.com/docs/stripe.js#stripe-create-token. createToken().then(data => console.log(data.token)) } }

So here’s what we’re going to do. We’re going to update the form to store the customer email, and update the pay method to send that and the token or error key to the Vuex store. We’ll dispatch an action to do so.

data() { return { ... stripeEmail: "" }; }, methods: { pay() { createToken().then(data => { const stripeData = { data, stripeEmail: this.stripeEmail }; this.$store.dispatch("postStripeFunction", stripeData); }); }, ...

That postStripeFunction action we dispatched looks like this:

// Vuex store
export const actions = { async postStripeFunction({ getters, commit }, payload) { commit("updateCartUI", "loading") try { await axios .post( "https://ecommerce-netlify.netlify.com/.netlify/functions/index", { stripeEmail: payload.stripeEmail, stripeAmt: Math.floor(getters.cartTotal * 100), //it expects the price in cents stripeToken: "tok_visa", //testing token, later we would use payload.data.token stripeIdempotency: uuidv1() //we use this library to create a unique id }, { headers: { "Content-Type": "application/json" } } ) .then(res => { if (res.status === 200) { commit("updateCartUI", "success") setTimeout(() => commit("clearCart"), 3000) …

We’re going to update the UI state to loading while we’re processing. Then we’ll use axios to post to our function endpoint (the URL you saw earlier in the post when we set up our function). We’ll send over the email, the amt, the token and the unique key that we built the function to expect.

Then if it was successful, we’ll update the UI state to reflect that.

One last note I’ll give is that I store the UI state in a string, rather than a boolean. I usually start it with something like “idle” and, in this case, I’ll also have “loading,” “success,” and “failure.” I don’t use boolean states because I’ve rarely encountered a situation where UI state only has two states. When you work with booleans for this purpose, you tend to need to break it out into more and more states, and checking for all of them can get increasingly complicated.

As it stands, I can reflect changes in the UI on the cart page with legible conditionals, like this:

<section v-if="cartUIStatus === 'idle'"> <app-cart-display />
</section> <section v-else-if="cartUIStatus === 'loading'" class="loader"> <app-loader />
</section> <section v-else-if="cartUIStatus === 'success'" class="success"> <h2>Success!</h2> <p>Thank you for your purchase. You'll be receiving your items in 4 business days.</p> <p>Forgot something?</p> <button class="pay-with-stripe"> <nuxt-link exact to="/">Back to Home</nuxt-link> </button>
</section> <section v-else-if="cartUIStatus === 'failure'"> <p>Oops, something went wrong. Redirecting you to your cart to try again.</p>

And there you have it! We’re all set up and running to accept payments with stripe on a Nuxt, Vue site with a Netlify function, and it wasn’t even that complicated to set up!

Gatsby Applications

We used Nuxt in this instance but if you wanted to set up the same kind of functionality with something that uses React such as Gatsby, there’s a plugin for that. (Everything is plugin in Gatsby. ☺️)

You would install it with this command:

yarn add gatsby-plugin-netlify-functions

…and add the plugin to your application like this:

plugins: [ { resolve: `gatsby-plugin-netlify-functions`, options: { functionsSrc: `${__dirname}/src/functions`, functionsOutput: `${__dirname}/functions`, }, },

The serverless function used in this demo is straight up JavaScript, so it’s also portable to React applications. There’s a plugin to add the Stripe script to your Gatsby app (again, everything is a plugin). Fair warning: this adds the script to every page on the site. To collect the credit card information on the client, you would use React Stripe Elements, which is similar to the Vue one we used above.

Just make sure that you’re collecting from the client and passing all the information the function is expecting:

  • The user email
  • The total amount, in cents
  • The token
  • The idempotency key

With such a low barrier to entry, you can see how you can make really dynamic experiences with JAMstack applications. It’s amazing how much you can accomplish without any maintenance costs from servers. Stripe and Netlify Functions make setting up payment processing in a static application such a smooth developer experience!

The post Let’s Build a JAMstack E-Commerce Store with Netlify Functions appeared first on CSS-Tricks.

How To Build A Real-Time Multiplayer Virtual Reality Game (Part 1)

How To Build A Real-Time Multiplayer Virtual Reality Game (Part 1)

How To Build A Real-Time Multiplayer Virtual Reality Game (Part 1)

Alvin Wan

In this tutorial series, we will build a web-based multiplayer virtual reality game in which players will need to collaborate to solve a puzzle. We will use A-Frame for VR modeling, MirrorVR for cross-device real-time synchronization, and A-Frame Low Poly for low-poly aesthetics. At the end of this tutorial, you will have a fully functioning demo online that anyone can play.

Each pair of players is given a ring of orbs. The goal is to “turn on” all orbs, where an orb is “on” if it’s elevated and bright. An orb is “off” if it’s lower and dim. However, certain “dominant” orbs affect their neighbors: if it switches state, its neighbors also switch state. Only player 2 can control the dominant orbs while only player 1 can control non-dominant orbs. This forces both players to collaborate to solve the puzzle. In this first part of the tutorial, we will build the environment and add the design elements for our VR game.

The seven steps in this tutorial are grouped into three sections:

  1. Setting Up The Scene (Steps 1–2)
  2. Creating The Orbs (Steps 3–5)
  3. Making The Orbs Interactive (Steps 6–7)

This first part will conclude with a clickable orb that turns on and off (as pictured below). You will use A-Frame VR and several A-Frame extensions.

(Large preview)

Setting Up The Scene

1. Let’s Go With A Basic Scene

To get started, let’s take a look at how we can set up a simple scene with a ground:

Creating a simple scene
Creating a simple scene (Large preview)

The first three instructions below are excerpted from my previous article. You will start by setting up a website with a single static HTML page. This allows you to code from your desktop and automatically deploy to the web. The deployed website can then be loaded on your mobile phone and placed inside a VR headset. Alternatively, the deployed website can be loaded by a standalone VR headset.

Get started by navigating to glitch.com. Then, do the following:

  1. Click on “New Project” in the top right,
  2. Click on “hello-webpage” in the drop-down,
  3. Next, click on index.html in the left sidebar. We will refer to this as your “editor”.

You should now see the following Glitch screen with a default HTML file.

Glitch project: the index.html file
Glitch project: the index.html file (Large preview)

As with the linked tutorial above, start by deleting all existing code in the current index.html file. Then, type in the following for a basic webVR project, using A-Frame VR. This creates an empty scene by using A-Frame’s default lighting and camera.

<!DOCTYPE html>
<html> <head> <title>Lightful</title> https://aframe.io/releases/0.8.0/aframe.min.js </head> <body> <a-scene> </a-scene> </body>

Raise the camera to standing height. Per A-Frame VR recommendations (Github issue), wrap the camera with a new entity and move the parent entity instead of the camera directly. Between your a-scene tags on lines 8 and 9, add the following.

<!-- Camera! -->
<a-entity id="rig" position="0 3 0"> <a-camera wasd-controls look-controls></a-camera>

Next, add a large box to denote the ground, using a-box. Place this directly beneath your camera from the previous instruction.

<!-- Action! -->
<a-box shadow width="75" height="0.1" depth="75" position="0 -1 0" color="#222"></a-box>

Your index.html file should now match the following exactly. You can find the full source code here, on Github.

<html> <head> <title>Lightful</title> https://aframe.io/releases/0.8.0/aframe.min.js </head> <body> <a-scene> <!-- Camera! --> <a-entity id="rig" position="0 3 0"> <a-camera wasd-controls look-controls></a-camera> </a-entity> <!-- Action! --> <a-box shadow width="75" height="0.1" depth="75" position="0 -1 0" color="#222"></a-box> </a-scene> </body>

This concludes setup. Next, we will customize lighting for a more mysterious atmosphere.

2. Add Atmosphere

In this step, we will set up the fog and custom lighting.

A preview of a simple scene with a dark mood
A preview of a simple scene with a dark mood (Large preview)

Add a fog, which will obscure objects far away for us. Modify the a-scene tag on line 8. Here, we will add a dark fog that quickly obscures the edges of the ground, giving the effect of a distant horizon.

<a-scene fog="type: linear; color: #111; near:10; far:15"></a-scene>

The dark gray #111 fades in linearly from a distance of 10 to a distance of 15. All objects more than 15 units away are completely obscured, and all objects fewer than 10 units away are completely visible. Any object in between is partially obscured.

Add one ambient light to lighten in-game objects and one-directional light to accentuate reflective surfaces you will add later. Place this directly after the a-scene tag you modified in the previous instruction.

<!-- Lights! -->
<a-light type="directional" castshadow="true" intensity="0.5" color="#FFF" position="2 5 0"></a-light>
<a-light intensity="0.1" type="ambient" position="1 1 1" color="#FFF"></a-light>

Directly beneath the lights in the previous instruction, add a dark sky. Notice the dark gray #111 matches that of the distant fog.

<a-sky color="#111"></a-sky>

This concludes basic modifications to the mood and more broadly, scene setup. Check that your code matches the source code for Step 2 on Github, exactly. Next, we will add a low-poly orb and begin customizing the orb’s aesthetics.

Creating The Orbs

3. Create A Low-Poly Orb

In this step, we will create a rotating, reflective orb as pictured below. The orb is composed of two stylized low-poly spheres with a few tricks to suggest reflective material.

Rotating, reflective orb
(Large preview)

Start by importing the low-poly library in your head tag. Insert the following between lines 4 and 5.

Create a carousel, wrapper, and orb container. The carousel will contain multiple orbs, the wrapper will allow us to rotate all orbs around a center axis without rotating each orb individually, and the container will — as the name suggests — contain all orb components.

<a-entity id="carousel"> <a-entity rotation="0 90 0" id="template" class="wrapper" position="0 0 0"> <a-entity id="container-orb0" class="container" position="8 3 0" scale="1 1 1"> <!-- place orb here --> </a-entity> </a-entity>

Inside the orb container, add the orb itself: one sphere is slightly translucent and offset, and the other is completely solid. The two combined mimic reflective surfaces.

<a-entity class="orb" id="orb0" data-id="0"> <lp-sphere seed="0" shadow max-amplitude="1 1 1" position="-0.5 0 -0.5"></lp-sphere> <lp-sphere seed="0" shadow max-amplitude="1 1 1" rotation="0 45 45" opacity="0.5" position="-0.5 0 -0.5"></lp-sphere>

Finally, rotate the sphere indefinitely by adding the following a-animation tag immediately after the lp-sphere inside the .orb entity in the last instruction.

<a-animation attribute="rotation" repeat="indefinite" from="0 0 0" to="0 360 0" dur="5000"></a-animation>

Your source code for the orb wrappers and the orb itself should match the following exactly.

<a-entity id="carousel"> <a-entity rotation="0 90 0" id="template" class="wrapper" position="0 0 0"> <a-entity id="container-orb0" class="container" position="8 3 0" scale="1 1 1"> <a-entity class="orb" id="orb0" data-id="0"> <lp-sphere seed="0" shadow max-amplitude="1 1 1" position="-0.5 0 -0.5"></lp-sphere> <lp-sphere seed="0" shadow max-amplitude="1 1 1" rotation="0 45 45" opacity="0.5" position="-0.5 0 -0.5"></lp-sphere> <a-animation attribute="rotation" repeat="indefinite" from="0 0 0" to="0 360 0" dur="5000"></a-animation> </a-entity> </a-entity> </a-entity>

Check that your source code matches the full source code for step 3 on Github. Your preview should now match the following.

Rotating, reflective orb
(Large preview)

Next, we will add more lighting to the orb for a golden hue.

4. Light Up The Orb

In this step, we will add two lights, one colored and one white. This produces the following effect.

Orb lit with point lights
(Large preview)

Start by adding the white light to illuminate the object from below. We will use a point light. Directly before #orb0 but within #container-orb0, add the following offset point light.

<a-entity position="-2 -1 0"> <a-light distance="8" type="point" color="#FFF" intensity="0.8"></a-light>

In your preview, you will see the following.

Orb lit with white point light
(Large preview)

By default, lights do not decay with distance. By adding distance="8", we ensure that the light fully decays with a distance of 8 units, to prevent the point light from illuminating the entire scene. Next, add the golden light. Add the following directly above the last light.

<a-light class="light-orb" id="light-orb0" distance="8" type="point" color="#f90" intensity="1"></a-light>

Check that your code matches the source code for step 4 exactly. Your preview will now match the following.

Orb lit with point lights
(Large preview)

Next, you will make your final aesthetic modification to the orb and add rotating rings.

5. Add Rings

In this step, you will produce the final orb, as pictured below.

Golden orb with multiple rings
(Large preview)

Add a ring in #container-orb0 directly before #orb0.

<a-ring color="#fff" material="side:double" position="0 0.5 0" radius-inner="1.9" radius-outer="2" opacity="0.25"></a-ring>

Notice the ring itself does not contain color, as the color will be imbued by the point light in the previous step. Furthermore, the material="side:double" is important as, without it, the ring’s backside would not be rendered; this means the ring would disappear for half of its rotation.

However, the preview with only the above code will not look any different. This is because the ring is currently perpendicular to the screen. Thus, only the ring’s “side” (which has 0 thickness) is visible. Place the following animation in between the a-ring tags in the previous instruction.

<a-animation attribute="rotation" easing="linear" repeat="indefinite" from="0 0 0" to="0 360 0" dur="8000"></a-animation>

Your preview should now match the following:

Golden orb with ring
(Large preview)

Create a variable number of rings with different rotation axes, speeds, and sizes. You can use the following example rings. Any new rings should be placed underneath the last a-ring.

<a-ring color="#fff" material="side:double" position="0 0.5 0" radius-inner="2.4" radius-outer="2.5" opacity="0.25"> <a-animation attribute="rotation" easing="linear" repeat="indefinite" from="0 45 0" to="360 45 0" dur="8000"></a-animation>
<a-ring color="#fff" material="side:double" position="0 0.5 0" radius-inner="1.4" radius-outer="1.5" opacity="0.25"> <a-animation attribute="rotation" easing="linear" repeat="indefinite" from="0 -60 0" to="-360 -60 0" dur="3000"></a-animation>

Your preview will now match the following.

Golden orb with multiple rings
(Large preview)

Check that your code matches the source code for step 5 on Github. This concludes decor for the orb. With the orb finished, we will next add interactivity to the orb. In the next step, we will specifically add a visible cursor with a clicking animation when pointed at clickable objects.

Making The Orbs Interactive

6. Add A Cursor

In this step, we will add a white cursor that can trigger clickable objects. The cursor is pictured below.

clicking on orb
(Large preview)

In your a-camera tag, add the following entity. The fuse attribute allows this entity the ability to trigger click events. The raycaster attribute determines how often and how far to check for clickable objects. The objects attribute accepts a selector to determine which entities are clickable. In this case, all objects of class clickable are clickable.

<a-entity cursor="fuse: true; fuseTimeout: 250" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.03; radiusOuter: 0.04" material="color: white; shader: flat; opacity: 0.5" scale="0.5 0.5 0.5" raycaster="far: 20; interval: 1000; objects: .clickable"> <!-- Place cursor animation here -->

Next, add cursor animation and an extra ring for aesthetics. Place the following inside the entity cursor object above. This adds animation to the cursor object so that clicks are visible.

<a-circle radius="0.01" color="#FFF" opacity="0.5" material="shader: flat"></a-circle>
<a-animation begin="fusing" easing="ease-in" attribute="scale" fill="backwards" from="1 1 1" to="0.2 0.2 0.2" dur="250"></a-animation>

Next, add the clickable class to the #orb0 to match the following.

<a-entity class="orb clickable" id="orb0" data-id="0">

Check that your code matches the source code for Step 6 on Github. In your preview, drag your cursor off of them onto the orb to see the click animation in action. This is pictured below.

clicking on orb
(Large preview)

Note the clickable attribute was added to the orb itself and not the orb container. This is to prevent the rings from becoming clickable objects. This way, the user must click on the spheres that make up the orb itself.

In our final step for this part, you will add animation to control the on and off states for the orb.

7. Add Orb States

In this step, you will animate the orb in and out of an off state on click. This is pictured below.

Interactive orb responding to clicks
(Large preview)

To start, you will shrink and lower the orb to the ground. Add a-animation tags to the #container-orb0 right after #orb0. Both animations are triggered by a click and share the same easing function ease-elastic for a slight bounce.

<a-animation class="animation-scale" easing="ease-elastic" begin="click" attribute="scale" from="0.5 0.5 0.5" to="1 1 1" direction="alternate" dur="2000"></a-animation>
<a-animation class="animation-position" easing="ease-elastic" begin="click" attribute="position" from="8 0.5 0" to="8 3 0" direction="alternate" dur="2000"></a-animation>

To further emphasize the off state, we will remove the golden point light when the orb is off. However, the orb’s lights are placed outside of the orb object. Thus, the click event is not passed to the lights when the orb is clicked. To circumvent this issue, we will use some light Javascript to pass the click event to the light. Place the following animation tag in #light-orb0. The light is triggered by a custom switch event.

<a-animation class="animation-intensity" begin="switch" attribute="intensity" from="0" to="1" direction="alternate"></a-animation>

Next, add the following click event listener to the #container-orb0. This will relay the clicks to the orb lights.

<a-entity id="container-orb0" ... onclick="document.querySelector('#light-orb0').emit('switch');">

Check that your code matches the source code for Step 7 on Github. Finally, pull up your preview, and move the cursor on and off the orb to toggle between off and on states. This is pictured below.

Interactive orb responding to clicks
(Large preview)

This concludes the orb’s interactivity. The player can now turn orbs on and off at will, with self-explanatory on and off states.


In this tutorial, you built a simple orb with on and off states, which can be toggled by a VR-headset-friendly cursor click. With a number of different lighting techniques and animations, you were able to distinguish between the two states. This concludes the virtual reality design elements for the orbs. In the next part of the tutorial, we will populate the orbs dynamically, add game mechanics, and set up a communication protocol between a pair of players.

Smashing Editorial (rb, dm, il)
Bounce Element Around Viewport in CSS

Let’s say you were gonna bounce an element all around a screen, sorta like an old school screensaver or Pong or something.

You’d probably be tracking the X location of the element, increasing or decreasing it in a time loop and — when the element reached the maximum or minimum value — it would reverse direction. Then do that same thing with the Y location and you’ve got the effect we’re after. Simple enough with some JavaScript and math.

Here’s The Coding Train explaining it clearly:

Here’s a canvas implementation. It’s Pong so it factors in paddles and is slightly more complicated, but the basic math is still there:

See the Pen
by Joseph Gutierrez (@DerBaumeister)
on CodePen.

But what if we wanted to do this purely in CSS? We could write @keyframes that move the transform or left/top properties… but what values would we use? If we’re trying to bounce around the entire screen (viewport), we’d need to know the dimensions of the screen and then use those values. But we never know that exact size in CSS.

Or do we?

CSS has viewport units, which are based on the size of the entire viewport. Plus, we’ve got calc() and we presumably know the size of our own element.

That’s the clever root of Scott Kellum’s demo:

See the Pen
Codepen screensaver
by Scott Kellum (@scottkellum)
on CodePen.

The extra tricky part is breaking the X animation and the Y animation apart into two separate animations (one on a parent and one on a child) so that, when the direction reverses, it can happen independently and it looks more screensaver-like.

:root { --width: 300px; --x-speed: 13s; --y-speed: 7s; --transition-speed: 2.2s;
} .el { width: var(--width); height: var(--width);
} .x { animation: x var(--x-speed) linear infinite alternate;
.y { animation: y var(--y-speed) linear infinite alternate;
} @keyframes x { 100% { transform: translateX(calc(100vw - var(--width))); }
@keyframes y { 100% { transform: translateY(calc(100vh - var(--width))); }

I stole that idea, and added some blobbiness and an extra element for this little demo:

See the Pen
Morphing Blogs with `border-radius`
by Chris Coyier (@chriscoyier)
on CodePen.

The post Bounce Element Around Viewport in CSS appeared first on CSS-Tricks.

Pitching Your Writing To Publications

Pitching Your Writing To Publications

Pitching Your Writing To Publications

Rachel Andrew

Recently, I had a chat with Chris Coyier and Dave Rupert over on the Shoptalk Podcast about writing for publications such as Smashing Magazine and CSS-Tricks. One of the things we talked about was submitting ideas to publications — something that can feel quite daunting even as an experienced writer.

In this article, I’m going to go through the process for pitching, heavily based on my own experience as a writer and as Editor in Chief of Smashing. However, I’ve also taken a look at the guidelines for other publications in order to help you find the right places to pitch your article ideas.

Do Your Research

Read existing articles on the site that you would like to write for. Who do they seem to be aimed at? What tone of voice do the writers take? Does the publication tend to publish news pieces, opinion, or how-to tutorials? Check to see if there are already other pieces which are on the same subject as your idea, i.e. will your piece add to the conversation already started by those articles? If you can show that you are aware of existing content on a particular subject, and explain how you will reference it or add to that information, the editor will know you have done some research.

Research more widely; are there already good pieces on the subject that an editor will consider your piece to be a repeat of? There is always space for a new take on an issue, but in general, publications want fresh material. You should be ready to explain how your piece will reference this earlier work and build upon it, or introduce the subject to a new audience.

A good example from our own archives is the piece, “Replacing jQuery With Vue.js”. There are a lot of introductions to Vue.js, however, this piece was squarely aimed at the web developer who knows jQuery. It introduced the subject in a familiar way specifically for the target audience.

Find The Submission Guide

The next thing to do is to find the submission information on the site you want to write for. Most publications will have information about who to contact and what information to include. From my point of view, simply following that information and demonstrating you have done some research puts you pretty high up the queue to be taken seriously. At Smashing Magazine, we have a link to the guide to writing for us right there on the contact form. I’d estimate that only 20% of people read and follow those instructions.

Screenshot of the Smashing Contact Form
The link to our submission guide on our Contact Us page.

When you submit your idea, it is up to you to sell it to the publication. Why should I run with your idea over the many others that will show up today? Spending time over your submissions will make a huge difference in how many pieces you have accepted.

Different publications have different requirements. At Smashing Magazine, we ask you to send an outline first, along with some information about you so that we can understand your expertise in the subject matter. We’re very keen to feature new voices, and so we’ll accept pieces from writers who haven’t got a huge string of writing credentials.

The information we request helps us to decide if you are likely to be able to deliver a coherent piece. As our articles are technical in nature (often tutorials), I find that an outline is the best way to quickly see the shape of the proposal and the scope it will cover. A good outline will include the main headings or sections of the article, along with an explanation of what will be taught in that section.

For many other publications, a common request is for you to send a pitch for the article. This would typically be a couple of paragraphs explaining the direction your piece will take. Once again, check the submission guide for any specific details that publication is interested to see.

The Verge has an excellent submission guide which explains exactly what they want to see in a pitch:

“A good pitch contains a story, a narrative backbone. Pitches should clearly and concisely convey the story you plan to write and why it matters. The best pitches display promising pre-reporting and deep knowledge of the topic as well as a sense of the angle or insight you plan to pursue. If your story depends on access to a person or company, you should say whether you have obtained it already (and if not, what your prospects are). Pitches should also be written in the style you expect to write the story.”

— “How To Pitch The Verge,” The Verge

A List Apart explains what they will accept in their contribution page:

“… a rough draft, a partial draft, or a short pitch (a paragraph or two summarizing your argument and why it matters to our readers) paired with an outline. The more complete your submission is, the better feedback we can give you.”

— “Write For Us,” A List Apart

The Slate has a list of Do’s and Don’ts for pitching:

“Do distill your idea into a pitch, even if you have a full draft already written. If you happen to have a draft ready, feel free to attach it, but please make sure you still include a full pitch describing the piece in the body of the email.”

— “How To Pitch Slate,” The Slate

Including your pitch or outline in the body of the email is a common theme of pitch guidelines. Remember that your aim is to make it as easy as possible for the editor to think, “that looks interesting”.

Include A Short Biography

The editor doesn’t need your life story, however, a couple of sentences about you is helpful. This is especially useful if you are a newer writer who has subject matter expertise but fewer writing credentials. If you are proposing an article to me about moving a site from WordPress to Gatsby, and tell me that the article is based on your experience of doing this on a large site, that is more interesting to me than a more experienced writer who has just thought it would be a good topic to write about.

If you do have writing credits, a few relevant links are more helpful than a link to your entire portfolio.

When You Can’t Find A Submission Guide

Some publications will publish an email address or contact form for submissions, but have no obvious guide. In that case, assume that a short pitch as described above is appropriate. Include the pitch in the body of the email rather than an attachment, and make sure you include contact details in addition to your email address.

If you can’t find any information about submitting, then check to see if the publication is actually accepting external posts. Are all the articles written by staff? If unsure, then get in touch via a published contact method and ask if they accept pitches.

I’ve Already Written My Article, Why Should I Send An Outline Or Pitch?

We ask for an outline for a few reasons. Firstly, we’re a very small team. Each proposal is assessed by me, and I don’t have time in the day to read numerous 3000-word first draft proposals. In addition, we often have around 100 articles in the writing process at any one time. It’s quite likely that two authors will want to write on the same subject.

On receiving an outline, if it is going in a similar direction to something we already have in the pipeline, I can often spot something that would add to — rather than repeat — the other piece. We can then guide you towards that direction, and be able to accept the proposal where a completed piece may have been rejected as too similar.

If you are a new writer, the ability to structure an outline tells me a lot about your ability to deliver us something useful. We are going to spend time and energy working with you on your article, and I want to know it will be worthwhile for all of us.

If you are an experienced writer, the fact that you have read and worked with our guidelines tells me a lot about you as a professional. Are you going to be difficult for our editorial team to work with and refuse to make requested changes? Or are you keen to work with us to shape a piece that will be most useful and practical for the audience?

In The Verge submission guide included above, they ask you to “clearly and concisely” convey the story you plan to write. Your pitch shouldn’t be an article with bits removed or about the first two paragraphs. It’s literally a sales pitch for your proposed article; your job is to make the editor excited to read your full proposal! Some publications — in particular those that publish timely pieces on news topics — will ask you to attach your draft along with the pitch, however, you still need to get the editor to think it is worth opening that document.

Promoting Yourself Or Your Business

In many guides to self-promotion or bootstrapping the promotion of a startup, writing guest posts is something that will often be suggested. Be aware that the majority of publications are not going to publish an advert and pay you for the privilege.

Writing an article that refers to your product may be appropriate, as most of our expertise comes from doing the job that we do. It is worth being upfront when proposing a piece that would need to mention your product or the product of the company you work for. Explain how your idea will not be an advert for the company and that the product will only be mentioned in the context of the experience gained in your work.

Some publications will accept a trade of an article for some promotion. CSS-Tricks is one such publication, and describes what they are looking for as follows:

“The article is intended to promote something. In that case, no money changes hands. In this scenario, your pitch must be different from a sponsored post in that you aren’t just straight up pitching your product or service and that you’re writing a useful article about the web; it just so happens to be something that the promotion you’ll get from this article is valuable to you.”

— “Guest Posting,” CSS-Tricks

Writing for a popular publication will give you a byline, i.e. your credit as an author. That will generally give you at least one link to your own site. Writing well-received articles can be a way to build up your reputation and even introduce people to your products and services, but if you try and slide an advert in as an article, you can be sure that editors are very well used to spotting that!

Pitching The Same Idea To Multiple Publications

For time-sensitive pieces, you might be keen to spread the net. In that case, you should make publications aware of submitting that you have submitted it elsewhere. Otherwise, it is generally good practice to wait for a response before offering the piece to another publication. The Slate writes,

“Do be mindful if you pitch your idea to multiple publications. We try to reply to everyone in a timely manner, typically within one to two days. As a general rule, and if the story isn’t too timely, it’s best to wait that amount of time before sharing the pitch with another publication. If you do decide to cast a wide net, it’s always helpful to let us know ahead of time so we can respond accordingly.”

— “How To Pitch Slate,” The Slate

If Your Pitch Is Rejected

You will have ideas rejected. Sometimes, the editor will let you know why, but most often you’ll get a quick no, thanks. Try not to take these to heart; there are many reasons why the piece might be rejected that have nothing to do with the article idea or the quality of your proposal.

The main reasons I reject pitches are as follows:

  1. Obvious Spam
    This is the easy one. People wanting to publish a “guest post” on vague subjects, and people wanting “do-follow links”. We don’t tend to reply to these as they are essentially spam.
  2. No Attempt At A Serious Outline
    I can’t tell anything about an idea from two sentences or three bullet points, and if the author can’t spend the time to write an outline, I don’t think I want to have a team member working with them.
  3. Not A Good Topic For Us
    There are some outlines that I can’t ever see being a great fit for our readers.
  4. An Attempt To Hide An Advert
    In this case, I’ll suggest that you talk to our advertising team!
  5. Difficult To Work With
    Last but not least, authors who have behaved so badly during the pitch process that I can’t bring myself to inflict them on anyone else. Don’t be that person!

If I have a decent outline on a relevant subject in front of me, then one of two things are going to happen: I’ll accept the outline and get the author into the writing process or I’ll reply to the author because there is some reason why we can’t accept the outline as it is. That will usually be because the target audience or tone is wrong, or we already have a very similar piece in development.

Quite often in these scenarios, I will suggest changes or a different approach. Many of those initial soft rejections become an accepted idea, or the author comes back with a different idea that does indeed work.

Ultimately, those of us who need to fill a publication with content really want you to bring us good ideas. To open my inbox and find interesting pitches for Smashing is a genuine highlight of my day. So please do write for us.

Things To Do

  • Research the publication, and the type of articles they publish;
  • Read their submissions guide, and follow it;
  • Be upfront if you have sent the pitch to other publications;
  • Include a couple of sentences about you, and why you are the person to write the article. Link to some other relevant writing if you have it;
  • Be polite and friendly, but concise.

Things To Avoid

  • Sending a complete draft along with the words, “How do I publish this on your site?”;
  • Sending things in a format other than suggested in the submissions guide;
  • Pitching a piece that is already published somewhere else;
  • Pitching a hidden advert for your product or services;
  • Following up aggressively, or sending the pitch to multiple editors, Facebook messenger, and Twitter, in an attempt to get noticed. We publish a pitch contact, because we want pitches. It might take a day or two to follow up though!

More Pitching Tips

Smashing Editorial (il)
20 Freshest Web Designs, August 2019

This month we leap back to the culture of America circa 1969, dive into the oceans with whales, discover multiple approaches to pitching a design agency, get invited to festivals, and shop online the right way. Enjoy!


Kilotype’s awesome new site shows off its variable fonts with a clever mouse-track — move your cursor around the screen vertically and horizontally to see the full range of each family’s weight and italic.

Once Upon a Time in Hollywood

The latest film from Tarantino is steeped in the culture of 1969, from the moon landing to Woodstock. This amazing promo-site does an incredible job of transporting you to a different era.

Wade and Leta

Wade and Leta are a partnership of talented art directors, whose offbeat sense of the absurd leads to some truly original and inspiring work. The homepage videos range from hilarious to bizarre.


If there’s one place I’d like to be right now, it’s floating around the coast of Menorca on beautiful traditional fishing boat, and that’s all thanks to this inspiring site for Balearic boat hire.

The Believer Magazine

The site for The Believer Magazine is charmingly counter-culture, with deceptively sophisticated typography and New Yorker-quality illustration. Exactly what you’d expect from a modern culture publication.

Cher Ami

Cher Ami’s site features plenty of engaging work, but it’s the little details that make this site special, like the way the menu flies out not-quite-square, and the hyperspace-style transitions.

Good Day

Good Day sells CBD-infused beverages from a tastefully minimal site. At roughly $6/drink, it’s not cheap, and this sophisticated site is ideal for positioning the company in the luxury consumables market.


Dice is a German music and arts festival. Its site features some incredible, generated organic shapes, with animated gradients to match, and the seamless eternal scroll is a delight.

Flatiron Collective

The Flatiron Collective site opens with animated illustration. It’s an eye-catching pitch for business, far into left-field from the usual agency promotional site, and doesn’t even showcase previous work.

Save Whales

Whales are among the most intelligent, graceful, and magical creatures in the world. This inspiring site features extraordinary photography and facts about the magnificent creatures.


InDnegev is an Israeli music festival with a psychedelic animated site. The site features bold color choices, subtle animation, and two people riding a giant fox made out of stars, because why not.

Gucci Marmont

One of the big trends in online shopping is 3D, and Gucci’s Marmont collection jumps on this trend with a 17th-century inspired art exhibition featuring its latest purses. Scroll to browse.


Oust is a leading creative agency with tons of amazing work. Instead of pressing its portfolio, Oust’s site shows off the energy and ambition of the company’s professional culture.


Gantri designs better lights, and its site is a glorious collection of careful ecommerce best practices and stellar product photography. This is exactly how you should sell products online.


Look Deeper is an eye health campaign from Australia that wants to educate you about the dangers your eyes face, with an impactful infographic style site highlighting the various threats to your eyesight.

Ada Sokół

Ada Sokół’s portfolio is designed to focus entirely on her unique brand of futuristic, 3D artwork. Alongside commercial work you’ll also find some exceptional personal work.


Embracing the www-ness of using three letters, where one would be too real-world, is Stuuudio, a design agency with a nice line in blobby-animated transitions. It’s a good take on the classic agency site.

Ocean Vagabond

Ocean Vagabond is a watersports company in Morocco. Its homepage features some small-scale video, but navigate to one of the location pages for inspiring video and typography interaction.


Festival is a vibrant and engaging one-pager for the Camberwell College of Art undergraduate degree show. With light-hearted typography and interactive confetti, it’s a great online invitation.

Neutral Works

Neutral Works is another design agency with a penchant for interesting, liquid-style transitions. Based in Japan, it’s fascinating to see the different approach to familiar products in a foreign culture.

p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

Popular Design News of the Week: August 12, 2019 – August 18, 2019

Every week users submit a lot of interesting stuff on our sister site Webdesigner News, highlighting great content from around the web that can be of interest to web designers. 

The best way to keep track of all the great stories and news being posted is simply to check out the Webdesigner News site, however, in case you missed some here’s a quick and useful compilation of the most popular designer news that we curated from the past week.

Note that this is only a very small selection of the links that were posted, so don’t miss out and subscribe to our newsletter and follow the site daily for all the news.

Image Optimization for the Web (2019 Guide)




Do Creatives Still Need Personal Websites?


Noted: New Logo for Lotus


How to Choose the Right Font for your Website


Adobe’s Next Big Bets are on AR and Mixed Reality Software


4 Rules for Intuitive UX


This YouTuber Redesigned the Logos of Starbucks, Coffee Bean, and Folgers-and They’re Brilliant


Beautiful Examples of Anime UI


Adobe Fresco: A Free App for the iPad Made to Beat Procreate


The Real Reason Snap Changed its Logo


5 Sneaky Typography Errors to Avoid


Uber Design Platform


WeWork Isn’t a Tech Company; It’s a Soap Opera


How Tinder Design Hooks You up


Here’s How Google’s New Keyword Selection Preferences Work


The Evolution of Visual Design and Tech’s Designer Renaissance


50+ Best Free Fonts for Minimal Design


Dieter Rams Designed One of Gillette’s Most Successful Razors


Three Years of Misery Inside Google, the Happiest Company in Tech


Designer Vs Corporation


Superposition: Use the Design System You Already Have


Finding Brand True North


The Four Critical Factors to Planning a Successful Project


UX Can’t Be Defined by One Set of “Rules”


Want more? No problem! Keep track of top design news from around the web with Webdesigner News.

p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

Draggin’ and Droppin’ in React

The React ecosystem offers us a lot of libraries that all are focused on the interaction of drag and drop. We have react-dnd, react-beautiful-dnd, react-drag-n-drop and many more, but some of them require quite a lot of work to build even a simple drag and drop demo, and some do not provide you with more complex functionality (e.g. multiple drag and drop instances), and if they do, it becomes very complex.

This is where react-sortable-hoc comes into play.

💡 This tutorial requires basic knowledge of React library and React hooks.

This library has “HOC” in its name for a good reason. It provides higher-order components that extends a component with drag and drop functionality.

Let’s walk through an implementation of its functionalities.

Spinning up a project

For this tutorial we are going to build an app with funny GIFs that can be dragged around the viewport.

GitHub Repo

Let’s create a simple app and add drag-n-drop functionality to it. We’re going to use create-react-app to spin up a new React project:

npx create-react-app your-project-name

Now let’s change to the project directory and install react-sorting-hoc and array-move. The latter is needed to move items in an array to different positions.

cd your-project-name
yarn add react-sortable-hoc array-move

Adding styles, data and GIF component

For simplicity’s sake, we are going to write all styles in our App.css file. You can overwrite styles you have there with the following ones:

.App { background: #1a1919; color: #fff; min-height: 100vh; padding: 25px; text-align: center;
} .App h1 { font-size: 52px; margin: 0;
} .App h2 { color: #f6c945; text-transform: uppercase;
} .App img { cursor: grab; height: 180px; width: 240px;

Let’s create our state with GIFs. For this purpose we gonna use React’s built-in useState hook:

import React, { useState } from 'react';

Now add following before the return statement:

const [gifs, setGifs] = useState([ 'https://media.giphy.com/media/3ohhwoWSCtJzznXbuo/giphy.gif', 'https://media.giphy.com/media/l46CbZ7KWEhN1oci4/giphy.gif', 'https://media.giphy.com/media/3ohzgD1wRxpvpkDCSI/giphy.gif', 'https://media.giphy.com/media/xT1XGYy9NPhWRPp4pq/giphy.gif',

It’s time to create our simple GIF component. Create a Gif.js file in the src directory and pass in the following code:

import React from 'react';
import PropTypes from 'prop-types'; const Gif = ({ gif }) => (<img src={gif} alt="gif" />) Gif.propTypes = { gif: PropTypes.string.isRequired,
}; export default Gif;

We always try to follow the best practices while writing code; thus we also import PropTypes for type checking.

Import the Gif component and add it to the main App component. With a bit of clean up, it looks like this:

import React, { useState } from 'react';
import './App.css'; import Gif from './Gif'; const App = () => { const [gifs, setGifs] = useState([ 'https://media.giphy.com/media/3ohhwoWSCtJzznXbuo/giphy.gif', 'https://media.giphy.com/media/l46CbZ7KWEhN1oci4/giphy.gif', 'https://media.giphy.com/media/3ohzgD1wRxpvpkDCSI/giphy.gif', 'https://media.giphy.com/media/xT1XGYy9NPhWRPp4pq/giphy.gif', ]); return ( 

Drag those GIFs around

Set 1

{gifs.map((gif, i) => )}
); } export default App;

Go to http://localhost:3000/ to see what the app looks like now:

A screenshot of react-sortable-hoc-article-app

Onto the drag-n-drop stuff

Alright, it’s time make our GIFs draggable! And droppable.

To start, we need two HOCs from react-sortable-hoc, and the >arrayMove method from the array-move library to modify our new array after dragging happens. We want our GIFs to stay on their new positions, right? Well, that’s what this is going to allow us to do.

Let’s import them:

import { sortableContainer, sortableElement } from 'react-sortable-hoc';
import arrayMove from 'array-move';

As you might have guessed, those components will be wrappers which will expose functionality needed for us.

  • sortableContainer is a container for our sortable elements.
  • sortableElement is a container for each single element we are rendering.

Let’s do the following after all our imports:

const SortableGifsContainer = sortableContainer(({ children }) => 
); const SortableGif = sortableElement(({ gif }) => <Gif key={gif} gif={gif} />);

We’ve just created a container for our children elements that would be passed inside our SortableGifsContainer and also created wrapper for a single Gif component.
If it’s a bit unclear to you, no worries — you will understand right after we implement it.

💡Note: You need to wrap your children in a div or any other valid HTML element.

It’s time to wrap our GIFs into the SortableGifsContainer and replace the Gif component with our newly created SortableGif:

<SortableGifsContainer axis="x" onSortEnd={onSortEnd}> {gifs.map((gif, i) => <SortableGif // don't forget to pass index prop with item index index={i} key={gif} gif={gif} /> )}

It’s important to note that you need to pass the index prop to your sortable element so the library can differentiate items. It’s similar to adding keys to the lists in React).

We add axis because our items are positioned horizontally and we want to drag them horizontally, while default is vertical dragging. In other words, we’re limiting dragging along the horizontal x-axis. As you can see we also add an onSortEnd function, which triggers every time we drag or sort our items around. There are, of course, a lot more events but you can find more info in the documentation which already does an excellent job of covering them.

Time to implement it! Add the following line above the return statement:

const onSortEnd = ({ oldIndex, newIndex }) => setGifs(arrayMove(gifs, oldIndex, newIndex));

I want to explain one more thing: our function received an old and new index of the item which was dragged and, of course, each time after we move items around we modify our initial array with the help of arrayMove.

Tada! Now you know how to implement drag-n-drop in your project. Now go and do it! 🎉 🎉 🎉

What if we have multiple lists of items?

As you can see, the previous example was relatively simple. You basically wrap each of the items in a sortable HOC and wrap it around with sortableContainer and, bingo, you’ve got basic drag and drop.

But how will we do it with multiple lists? The good news is that react-sortable-hoc provides us with a collection prop so we can differentiate between lists.

First, we should add second array of GIFs:

const [newGifs, setNewGifs] = useState([ 'https://media.giphy.com/media/xiOgHgY2ceKhm46cAj/giphy.gif', 'https://media.giphy.com/media/3oKIPuMqYfRsyJTWfu/giphy.gif', 'https://media.giphy.com/media/4ZgLPakqTajjVFOVqw/giphy.gif', 'https://media.giphy.com/media/3o7btXIelzs8nBnznG/giphy.gif',

If you want to see them before we move next, add the following lines after the SortableGifsContainer closing tag:

{newGifs.map(gif => <Gif key={gif} gif={gif} />)}

Alright, time to replace it with a draggable version.

Implementation is the same as in first example besides one thing — we have added a collection prop to our SortableGif. Of course, you can come up with any name for the collection, just remember, we’re gonna need it in for our onSortEnd function.

<h2>Set 2</h2> <SortableGifsContainer axis="x" onSortEnd={onSortEnd}> {newGifs.map((gif, i) => <SortableGif index={i} key={gif} gif={gif} collection="newGifs" />)}

Next we need to add the collection prop to our first list. I’ve chosen the name GIFs for the first list of items, but it’s up to you!

Now we need to to change our onSortEnd function. Our function received old and new indexes, but we can also destructure a collection from it. Right, exactly the one we’ve added to our SortableGif.

So all we have to do now is write a JavaScript switch statement to check for the collection name and to modify the right array of GIFs on drag.

const onSortEnd = ({ oldIndex, newIndex, collection }) => { switch(collection) { case 'gifs': setGifs(arrayMove(gifs, oldIndex, newIndex)) break; case 'newGifs': setNewGifs(arrayMove(newGifs, oldIndex, newIndex)) break; default: break; }

Time to check it out!

As you can see, we now have two separate lists of GIFs and we can drag and sort. Moreover, they are independent meaning items from different lists won’t be mixed up.

Exactly what we wanted to do! Now you know how to create and handle drag and drop with multiple lists of items. Congratulations 🎉

Hope you’ve enjoyed it as much as I did writing it! If you’d like to reference the complete code, it’s all up on GitHub here. If you have any questions, feel free to contact me via email.

The post Draggin’ and Droppin’ in React appeared first on CSS-Tricks.

Accessibility and web performance are not features, they’re the baseline

This week I’ve been brooding about web performance and accessibility. It all began when Ethan Marcotte made a lot of great notes about the accessibility issues that are common with AMP:

In the recordings above, I’m trying to navigate through the AMP Story. And as I do, VoiceOver describes a page that’s impossible to understand: the arrows to go back or forward are simply announced as “button”; most images are missing text equivalents, which is why the screen reader spells out each and every character of their filenames; and when a story’s content is visible on screen, it’s almost impossible to access. I’d like to say that this one AMP Story was an outlier, but each of the nine demos listed on the AMP Stories website sound just as incomprehensible in VoiceOver.

Ethan continues to argue that these issues are so common in AMP that accessibility must not be a priority at all:

Since the beginning, Google has insisted AMP is the best solution for the web’s performance problem. And Google’s used its market dominance to force publishers to adopt the framework, going so far as to suggest that AMP’s the only format you need to publish pages on the web. But we’ve reached a point where AMP may “solve” the web’s performance issues by supercharging the web’s accessibility problem, excluding even more people from accessing the content they deserve.

I’ve been thinking a lot about this lately — about how accessibility work is often seen as an additional feature that can be tacked onto a project later — rather than accessibility work being a core principle or standard of working on the web.

And I’ve seen this sentiment expressed time and time again, in the frameworks, on Twitter, in the design process, in the development process, and so much so that arguing about the importance of accessibility can get pretty exhausting. Because at some point we’re not arguing about the importance of accessibility but the importance of front-end development itself as a series of worthy skills to have. Skills that can’t be replaced.

Similarly, this post by Craig Mod, on why software should be lightning fast, had me thinking along the same lines:

I love fast software. That is, software speedy both in function and interface. Software with minimal to no lag between wanting to activate or manipulate something and the thing happening. Lightness.

Later in the piece, Mod describes fast software as being the very definition of good software and argues that every action on a computer — whether that’s a website or an app — should feel as if you’re moving without any latency whatsoever. And I couldn’t agree more; every loading screen and wait time is in some degree a mark of failure.

Alex Russell made a similar point not so long ago when he looked at the performance of mobile phones and examined how everyone experiences the web in a very different way:

The takeaway here is that you literally can’t afford desktop or iPhone levels of JS if you’re trying to make good web experiences for anyone but the world’s richest users, and that likely means re-evaluating your toolchain.

I’m sort of a jerk when it comes to this stuff. I don’t think a website can be good until it’s fast. The kind of fast that takes your breath away. As fast as human thought, or even faster. And so my point here is that web performance isn’t something we should aspire to, it should be the standard. The status quo. The baseline that our work is judged by. It ought to be un-shippable until the thing is fast.

The good news is that it’s easier than ever to ship a website with these base requirements of unparalleled speed and accessibility! We have Page Speed Insights, and Web Page Test, not to mention the ability to have Lighthouse perform audits with every commit in GitHub automatically as we work. Ire Aderinokun showed us how to do this not so long ago by setting up a performance budget and learning how to stick to it.

The tools to make our websites fast and accessible are here but we’re not using them. And that’s what makes me mad.

While I’m on this rant — and before I get off my particularly high horse — I think it’s important to make note of Deb Chachra’s argument that “any sufficiently advanced negligence is indistinguishable from malice.” With that in mind, it’s not just bad software design and development if a website is slow. Performance and accessibility aren’t features that can linger at the bottom of a Jira board to be considered later when it’s convenient.

Instead we must start to see inaccessible and slow websites for what they are: a form of cruelty. And if we want to build a web that is truly a World Wide Web, a place for all and everyone, a web that is accessible and fast for as many people as possible, and one that will outlive us all, then first we must make our websites something else altogether; we must make them kind.

The post Accessibility and web performance are not features, they’re the baseline appeared first on CSS-Tricks.

Monthly Web Development Update 8/2019: Strong Teams And Ethical Data Sensemaking

Monthly Web Development Update 8/2019: Strong Teams And Ethical Data Sensemaking

Monthly Web Development Update 8/2019: Strong Teams And Ethical Data Sensemaking

Anselm Hannemann

What’s more powerful than a star who knows everything? Well, a team not made of stars but of people who love what they do, stand behind their company’s vision and can work together, support each other. Like a galaxy made of stars — where not every star shines and also doesn’t need to. Everyone has their place, their own strength, their own weakness. Teams don’t consist only of stars, they consist of people, and the most important thing is that the work and life culture is great. So don’t do a moonshot if you’re hiring someone but try to look for someone who fits into your team and encourages, supports your team’s values and members.

In terms of your own life, take some time today to take a deep breath and recall what happened this week. Go through it day by day and appreciate the actions, the negative ones as well as the positive ones. Accept that negative things happen in our lives as well, otherwise we wouldn’t be able to feel good either. It’s a helpful exercise to balance your life, to have a way of invalidating the feeling of “I did nothing this week” or “I was quite unproductive.” It makes you understand why you might not have worked as much as you’re used to — but it feels fine because there’s a reason for it.


  • Three weeks ago we officially exhausted the Earth’s natural resources for the year — with four months left in 2019. Earth Overshoot Day is a good indicator of where we’re currently at in the fight against climate change and it’s a great initiative by people who try to give helpful advice on how we can move that date so one day in the (hopefully) near future we’ll reach overshoot day not before the end of the year or even in a new year.
  • Chrome 76 brings the prefers-color-scheme media query (e.g. for dark mode support) and multiple simplifications for PWA installation.



Web Performance

  • Some experiments sound silly but in reality, they’re not: Chris Ashton used the web for a day on a 50MB budget. In Zimbabwe, for example, where 1 GB costs an average of $75.20, ranging from $12.50 to $138.46, 50MB is incredibly expensive. So reducing your app bundle size, image size, and website cost are directly related to how happy your users are when they browse your site or use your service. If it costs them $3.76 (50MB) to access your new sports shoe teaser page, it’s unlikely that they will buy or recommend it.
  • BBC’s Toby Cox shares how they ditched iframes in favor of ShadowDOM to improve their site performance significantly. This is a good piece explaining the advantages and drawbacks of iframes and why adopting ShadowDOM takes time and still feels uncomfortable for most of us.
  • Craig Mod shares why people prefer to choose (and pay for) fast software. People are grateful for it and are easily annoyed if the app takes too much time to start or shows a laggy user interface.
  • Harry Roberts explains the details of the “time to first byte” metric and why it matters.



  • With Chrome 76 we get the loading attribute which allows for native lazy loading of images just with HTML. It’s great to have a handy article that explains how to use, debug, and test it on your website today.
Lazy loading images of cats
No more custom lazy-loading code or a separate JavaScript library needed: Chrome 76 comes with native lazy loading built in. (Image credit)



  • Here’s a technical analysis of the Capital One hack. A good read for anyone who uses Cloud providers like AWS for their systems because it all comes down to configuring accounts correctly to prevent hackers from gaining access due to a misconfigured cloud service user role.


Work & Life

  • For a long time I believed that a strong team is made of stars — extraordinary world-class individuals who can generate and execute ideas at a level no one else can. These days, I feel that a strong team is the one that feels more like a close family than a constellation of stars. A family where everybody has a sense of predictability, trust and respect for each other. A family which deeply embodies the values the company carries and reflects these values throughout their work. But also a family where everybody feels genuinely valued, happy and ignited to create,” said Vitaly Friedman in an update thought recently and I couldn’t agree more.
  • How do you justify a job in a company that has a significant influence on our world and our everyday lives and that not necessarily with the best intentions? Meredith Whittaker wrote up her story of starting at Google, having an amazing time there, and now leaving the company because she couldn’t justify it anymore that Google is using her work and technology to get involved in fossil energy business, healthcare, governance, and transportation business — and not always with the focus on improving everyone’s lives or making our environment a better place to live in but simply for profit.
  • Synchronous meetings are a problem in nearly every company. They take a lot of time from a lot of people and disrupt any schedule or focused work. So here’s how Buffer switched to asynchronous meetings, including great tips and insights into why many tools out there don’t work well.
  • Actionable advice is what we usually look for when reading an article. However, it’s not always possible or the best option to write actionable advice and certainly not always a good idea to follow actionable advice blindly. That’s because most of the time actionable advice also is opinionated, tailored, customized advice that doesn’t necessarily fit your purpose. Sharing experiences instead of actionable advice fosters creativity so everyone can find their own solution, their own advice.
  • Sam Clulow’s “Our Planet, Our Problem” is a great piece of writing that reminds us of who we are and what’s important for us and how we can live in a city and switch to a better, more thoughtful and natural life.
  • Climate change is a topic all around the world now and it seems that many people are concerned about it and want to take action. But then, last month we had the busiest air travel day ever in history. Airplanes are accountable for one of the biggest parts of climate active emissions, so it’s key to reduce air travel as much as possible from today on. Coincidentally, this was also the hottest week measured in Europe ever. We as individuals need to finally cut down on flights, regardless of how tempting that next $50-holiday-flight to a nice destination might be, regardless of if it’s an important business meeting. What do we have video conferencing solutions for? Why do people claim to work remotely if they then fly around the world dozens of times in their life? There are so many nice destinations nearby, reachable by train or, if needed, by car.
Update from a team member of what happened during the week and what he’s working on
The team at Buffer shares what worked and what didn’t work for them when they switched to asynchronous meetings. (Image credit)

Going Beyond…

  • Leo Babauta shares a tip on how to stop overthinking by cutting through indecision. We will never have the certainty we’d like to have in our lives so it’s quite good to have a strategy for dealing with uncertainty. As I’m struggling with this a lot, I found the article helpful.
  • The ethical practices that can serve as a code of conduct for data sensemaking professionals are built upon a single fundamental principle. It is the same principle that medical doctors swear as an oath before becoming licensed: Do no harm. Here’s “Ethical Data Sensemaking.”
  • Paul Hayes shares his experience from trying to live plastic-free for a month and why it’s hard to stick to it. It’s surprising how shopping habits need to be changed and why you need to spend your money in a totally different way and cannot rely on online stores anymore.
  • Oil powers the cars we drive and the flights we take, it heats many of our homes and offices. It is in the things we use every day and it plays an integral role across industries and economies. Yet it has become very clear that the relentless burning of fossil fuels cannot continue unabated. Can the world be less reliant on oil?
  • Uber and Lyft admit that they’re making traffic congestion worse in cities. Next time you use any of those new taxi apps, try to remind yourself that you’re making the situation worse for many people in the city.

Thank you for reading. If you like what I write, please consider supporting the Web Development Reading List.


Smashing Editorial (cm)
12 Best CMS for 2019

2019 is half over, but don’t let that stop you from trying something new… specifically, a new CMS. “But Ezequiel, good buddy, I don’t have time to check out a whole new content management system. I have websites to make!”, you say, in those exact words.

That’s fair, but you should be keeping an eye on the up-and comers anyway. These are the people who have the sheer brass walnuts (which are a real thing, unisex, and available to anyone with money) to go up against giants like WordPress, Joomla, and mostly WordPress. They do this with nothing but a pretty good idea, a GitHub repository, and sometimes some corporate funding of some kind, if they’re very lucky. You ignore them at your own peril.

Well, maybe not peril, but these projects deserve a look.

The CMS that have been selected for this list were (almost) all launched post-2017 (or at least their GitHub repos were), and they’re all free, or at least have a free plan. They’re also all under active development. Let’s get started…


Flextype is a simple, PHP7-based, flat-file CMS that’s designed to keep things flexible, allowing you to create more or less anything you want. And I do mean “anything”; Flextype makes it dead-easy to define custom fields for any content entry, and has a built-in theme editor

The actual content editing is easy enough, with a simple WYSIWYG editor, though Markdown support is available via plugin. Doing anything fancy with the content requires the use of WordPress-style shortcodes, though.

All in all, it’s a solid foundation for a CMS, and I can’t wait to see what they do with it.


rwtxt is designed to be a simple, searchable notepad where you can jot down notes, keep a journal, or use it as a pastebin. It’s reminiscent of a wiki in that, in its default configuration, anyone can add a page to the public area of the site.

However, you can also add a “domain”, or a sort of personal notepad where you can either keep your private notes private, or make them public and publicly searchable. You can also log into multiple domains at a time, so you could theoretically use rwtxt to run a site with multiple blogs that are thematically different. (You can also add custom CSS to a domain, for further differentiation.)

The whole experience is very bare-bones, but I’m fascinated to see where it goes.

Relevant: rwtxt Github Repo


Publii is one of a few new GUI-focused Static CMS apps that run on the desktop, rather than on your server. You download the app, use it to build a static site, then upload that site onto the hosting of your choice. It’s not a new idea, but it’s one that seems to have picked up steam, lately.

Publii in particular seems to be the most modern and feature-complete of these CMS, and is open source and free to use. It seems to be blog-focused, and there is a marketplace with both free and paid theme options of excellent quality.

Other features include website syncing (supports FTP, GitHub Pages, Gitlab, AWS, Netlify, or Google Cloud), a preview function, a WordPress importer, and a focus on SEO. It’s very definitely focused at more beginner-level users.


Speaking, however briefly, of WordPress, ClassicPress is literally a WordPress fork that notably lacks a certain block-based content editor that lots of people disliked. Otherwise, the current version aims to improve security and optimization, remove some bloat, and points the CMS squarely at business users who might be put off by quirky language such as “Howdy”.

The biggest difference so far, besides using the classic content editor, is the governance of the project; there’s a very large focus placed on democracy and voting to determine the future of the project, where WordPress’ future is largely written by Automattic (the company that makes it).


Twill isn’t strictly a CMS, as such. It’s a “CMS toolkit”, designed to help developers very quickly create a custom CMS to match any need. As such, it’s not something you’d want to install just to start your own blog.

But if you’re a developer, or a business owner who needs a custom-built CMS, it does look like a promising way to get exactly the functionality you need, faster. It’s based on the Laravel PHP framework, so if that’s something you already use and like, try it out.


CannerCMS is similar to Twill in that it’s a build-your-own CMS kit of sorts. Unlike Twill, it seems to be Node-based, so if writing JavaScript is more your style, CannerCMS has you covered.

Incidentally, they also has a SaaS version of the product, which takes care of all the hosting, CDN configuration, and other general hassles for you. The open source edition also apparently lacks multi-language support, which the SaaS version has.

Grafite CMS

Grafite CMS is a sort of dual purpose CMS. By that I mean you can use it as a standalone CMS, on its own and fully functional, or as an add-on to an existing site or web app. Now lots of CMS will allow you to do this via an API of some sort, but Grafite CMS actually comes with two separate setup/installation modes, depending on whether you want to use Grafite CMS on its own, or integrate it into something larger.

It’s also modular, in that content types like “Pages”, Blog”, “Events”, and other are modules that you can activate or deactivate at will. You can, of course, make your own modules if you need a custom content type. It’s very much based on a “use only what you need” philosophy.


Vapid has been mentioned once before here on Web Designer Depot, but it’s worth looking at again, in case you missed it. It’s billed as an intentionally simple CMS, and they mean it. The dashboard is literally generated based on the tags you use in your templates. Every time you mark part of a page as editable content, the dashboard will add the appropriate form field in the admin UI.

It’s written in NodeJS, and you can host the app on your own server for free if you know how (the code itself is open source), or you can deploy your website to Vapid’s own hosting service. Publishing your site there does cost money of course, but the plans are quite reasonable, with the first paid plan starting at 7 USD.


Zola is a static site generator written in Rust, so it does depend on using a command line interface, but otherwise, they keep development simple. I mean, when’s the last time you heard of a static site generator that didn’t have any dependencies? There are even premade binaries for Windows, Mac, and Linux, so installation is quick and simple.

So yeah, even if you’ve got only a rudimentary understanding of programming like myself, you can probably build sites with Zola. It’s got a list of features about a mile long, including custom taxonomies, LiveReload, Netlify support, shortcodes, image processing, and more. The content is all handled by Markdown, of course.


Academic is interesting because it’s a CMS built on top of another CMS. Specifically, it’s a website / page builder built on top of the Hugo static site generator. It’s designed to take the complexity of a static site generator, and make everything sort of drag and drop. And I do mean everything.

There’s support for easily managing custom pages, talks, slides, tutorials, as well as all the usual content types. There’s multilingual support, and everything can be written in Markdown and, interestingly enough, LaTeX if you’re the math-loving type. Existing themes mostly seem to be Material Design-based, but of course you can make your own.

Piranha CMS

I didn’t want our ASP.NET lovers out there feel like we’d forgotten them. For you, Piranha CMS looks rather promising. Interestingly for an ASP.NET CMS, it can run on Windows, Mac, and Linux, with a focus on speed and easy publishing. Considering the tech it’s based on, it’s also Azure-ready right out of the box, if that’s something that matters to you.

Besides all that, you can edit your content as HTML or Markdown, or even plain text. There’s also a Gutenberg-style block editor. There’s image processing, easy internal linking, and even easy ways to run multiple blogs on the same site. The whole thing seems to be aimed at big publishers.


Squidex is an ASP.NET-based open source headless CMS (that means they don’t dictate how any of your HTML gets output) that you can run on your own server, or use their SaaS option which also has a limited free plan. It’s the sort of CMS that’s meant to be used as a central repository for all of your content, which you can access anywhere via their API. So theoretically, you could use it to run multiple internal and / or external websites.

As such, it’s the sort of CMS where you sort of have to build your own dashboard, as well as the front end user interface. That said, it does look real good, and offers loads of options to help you build the CMS of your (apparently quite nerdy) dreams.


Featured image via Unsplash.

p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

Privacy Settings
We use cookies to enhance your experience while using our website. If you are using our Services via a browser you can restrict, block or remove cookies through your web browser settings. We also use content and scripts from third parties that may use tracking technologies. You can selectively provide your consent below to allow such third party embeds. For complete information about the cookies we use, data we collect and how we process them, please check our Privacy Policy
Consent to display content from Youtube
Consent to display content from Vimeo
Google Maps
Consent to display content from Google