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

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 more than 3 from the end. That would start with the fourth 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(n + 3) selects items that match the condition of being more than the third item from the end or greater.

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.

Build a state management system with vanilla JavaScript

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?

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:

<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.

Finite State Machines with React

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.

How to make a modern dashboard with NVD3.js

NVD3.js is a JavaScript visualization library that is free to use and open source. It’s derived from the well-known d3.js visualization library. When used the right way, this library can be extremely powerful for everyday tasks and even business operations.

For example, an online dashboard. We can use NVD3.js to compile data into a centralized space that visualizes the information in neat charts and graphs. That’s what we’re going to look at in this post.

Making a dashboard with NVD3.js for the first time is daunting, but after this tutorial, you should have the required knowledge to get your hands dirty and start building something awesome. Personally, I have a passion for visualizations on the web. They are both beautiful and meaningful at the same time.

Real-world use case: A data dashboard

Dashboards can be used for pretty much anything. As long as you’ve got data to analyze, you’re good to go, whether that be some sales data or the average weather for the last 20 years. Let’s build something like this:

See the Pen Dashboard NVD3.JS by Danny Englishby (@DanEnglishby) on CodePen.

Setting up the environment

To setup an NVD3 chart, we require three things:

  1. The NVD3 JavaScript library
  2. The NVD3 CSS library
  3. The D3.js library (a dependency for NVD3)

All of these are available through Cloudflare’s CDN network. Here’s an HTML template with all those resources ready to go:

<!doctype html>
<html lang="en">
<head> <meta charset="utf-8"> <title>Making a Dashboard</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.css">
</head>
<body> </body>
</html>

Data sources

For this tutorial, I thought using some raw, factual data that’s already been formatted into JSON would be easiest. I’m using two sources of information: one about global average temperatures over time and the other reporting world population statistics. I’ve already formatted the data into JSON, so it’s ready to copy and paste!

Creating a line chart

Let’s go ahead and create a line chart with some global temperature data. The raw data I’ve put together in JSON represents the last twenty years of temperature changes compared to the global average.

First, we’ll add a placeholder element for the chart to attach to when the JavaScript is executed.

<div id="averageDegreesLineChart" class='with-3d-shadow with-transitions averageDegreesLineChart'> <svg></svg>
</div>

Then add the following JSON in some script tags before the </body> tag:

var temperatureIndexJSON = [ { key: "Temp +- Avg.", values: [{ "x": 1998, "y": 0.45 }, { "x": 1999, "y": 0.48 }, { "x": 2000, "y": 0.5 }, { "x": 2001, "y": 0.52 }, { "x": 2002, "y": 0.55 }, { "x": 2003, "y": 0.58 }, { "x": 2004, "y": 0.6 }, { "x": 2005, "y": 0.61 }, { "x": 2006, "y": 0.61 }, { "x": 2007, "y": 0.61 }, { "x": 2008, "y": 0.62 }, { "x": 2009, "y": 0.62 }, { "x": 2010, "y": 0.62 }, { "x": 2011, "y": 0.63 }, { "x": 2012, "y": 0.67 }, { "x": 2013, "y": 0.71 }, { "x": 2014, "y": 0.77 }, { "x": 2015, "y": 0.83 }, { "x": 2016, "y": 0.89 }, { "x": 2017, "y": 0.95 }] }
];

The x value is the year and they value is the temperature in Celsius degrees.

The last piece to the puzzle is the most important function that creates the chart. The function named nv.addGraph() is the main function used throughout NVD3 and, within it, you initialize the chart object. In this example, we are using the lineChart object which can have methods chained to it, depending on what the visual requirements may be.

Check out the JavaScript comments to see the which each line does.

nv.addGraph(function () { var chart = nv.models.lineChart() // Initialise the lineChart object. .useInteractiveGuideline(true); // Turn on interactive guideline (tooltips) chart.xAxis .axisLabel('TimeStamp (Year)'); // Set the label of the xAxis (Vertical)
chart.yAxis .axisLabel('Degrees (c)') // Set the label of the xAxis (Horizontal) .tickFormat(d3.format('.02f')); // Rounded Numbers Format.
d3.select('#averageDegreesLineChart svg') // Select the ID of the html element we defined earlier. .datum(temperatureIndexJSON) // Pass in the JSON .transition().duration(500) // Set transition speed .call(chart); // Call & Render the chart nv.utils.windowResize(chart.update); // Intitiate listener for window resize so the chart responds and changes width. return;
});

See the Pen Line Chart NVD3.JS by Danny Englishby (@DanEnglishby) on CodePen.

Creating two bar charts for the price of one

You will love the minimal effort of these next two charts. The power of NVD3.js enables switching between chart types. You can either have the toggle active so users can switch between a standard bar chart or a stacked bar chart. Or you can force the chart type and make it unchangeable.

The following examples show exactly how to do it.

Stacked multi-bar chart

You know those bar charts that stack two values together in the same bar? That’s what we’re doing here.

<div id="worldPopulationMultiBar" class="with-3d-shadow with-transitions worldPopulationMultiBar"> <svg></svg>
</div>
var populationBySexAndCountryJSON =[{"key":"Male","color":"#d62728","values":[{"label":"China","value":717723466.166},{"label":"India","value":647356171.132},{"label":"United States of America","value":157464952.272},{"label":"Indonesia","value":125682412.393},{"label":"Brazil","value":98578067.1},{"label":"Pakistan","value":93621293.316},{"label":"Nigeria","value":88370210.605},{"label":"Bangladesh","value":79237050.772},{"label":"Russian Federation","value":65846330.629},{"label":"Japan","value":61918921.999}]},{"key":"Female","color":"#1f77b4","values":[{"label":"China","value":667843070.834},{"label":"India","value":604783424.868},{"label":"United States of America","value":162585763.728},{"label":"Indonesia","value":124183218.607},{"label":"Brazil","value":101783857.9},{"label":"Pakistan","value":88521300.684},{"label":"Nigeria","value":85245134.395},{"label":"Bangladesh","value":77357911.228},{"label":"Russian Federation","value":76987358.371},{"label":"Japan","value":65224655.001}]}]; nv.addGraph(function ()
{ var chart = nv.models.multiBarChart() .x(function (d) { return d.label; // Configure x axis to use the "label" within the json. }) .y(function (d) { return d.value; // Configure y axis to use the "value" within the json. }).margin({top: 30, right: 20, bottom: 50, left: 85}) // Add some CSS Margin to the chart. .showControls(false) // Turn of switchable control .stacked(true); // Force stacked mode. chart.xAxis.axisLabel('Countries'); // add label to the horizontal axis chart.yAxis.tickFormat(d3.format('0f')); // Round the yAxis values d3.select('#worldPopulationMultiBar svg') // Select the html element by ID .datum(populationBySexAndCountryJSON) // Pass in the data .transition().duration(500) // Set transition speed .call(chart); // Call & Render chart nv.utils.windowResize(chart.update); // Intitiate listener for window resize so the chart responds and changes width. return;
});

The two important settings in the JavaScript here are the .showControls and .stacked booleans. They both do what they say on the tin: force the graph to a stacked bar chart and don’t allow switching of the chart type. You will see what I mean by switching soon.

See the Pen Multi StackedBar NVD3.JS by Danny Englishby (@DanEnglishby) on CodePen.

Standard multi-bar chart

Now, let’s do something a little more traditional and compare values side-by-side instead of stacking them in the same bar.

This uses pretty much the same code as the stacked examples, but we can change the .stacked boolean value to false. This will, of course, make the stacked bar chart a normal bar chart.

<div id="worldPopulationMultiBar" class="with-3d-shadow with-transitions worldPopulationMultiBar"> <svg></svg>
</div>
var populationBySexAndCountryJSON = [{"key":"Male","color":"#d62728","values":[{"label":"China","value":717723466.166},{"label":"India","value":647356171.132},{"label":"United States of America","value":157464952.272},{"label":"Indonesia","value":125682412.393},{"label":"Brazil","value":98578067.1},{"label":"Pakistan","value":93621293.316},{"label":"Nigeria","value":88370210.605},{"label":"Bangladesh","value":79237050.772},{"label":"Russian Federation","value":65846330.629},{"label":"Japan","value":61918921.999}]},{"key":"Female","color":"#1f77b4","values":[{"label":"China","value":667843070.834},{"label":"India","value":604783424.868},{"label":"United States of America","value":162585763.728},{"label":"Indonesia","value":124183218.607},{"label":"Brazil","value":101783857.9},{"label":"Pakistan","value":88521300.684},{"label":"Nigeria","value":85245134.395},{"label":"Bangladesh","value":77357911.228},{"label":"Russian Federation","value":76987358.371},{"label":"Japan","value":65224655.001}]}]; nv.addGraph(function () { var chart = nv.models.multiBarChart() .x(function (d) { return d.label; // Configure x axis to use the "label" within the json. }) .y(function (d) { return d.value; // Configure y axis to use the "value" within the json. }).margin({top: 30, right: 20, bottom: 50, left: 85}) // Add some CSS Margin to the chart. .showControls(false) // Turn of switchable control .stacked(false); // ***Force normal bar mode.*** chart.xAxis.axisLabel('Countries'); // add label to the horizontal axis chart.yAxis.tickFormat(d3.format('0f')); // Round the yAxis values d3.select('#worldPopulationMultiBar svg') // Select the html element by ID .datum(populationBySexAndCountryJSON) // Pass in the data .transition().duration(500) // Set transition speed .call(chart); // Call & Render chart nv.utils.windowResize(chart.update); // Intitiate listener for window resize so the chart responds and changes width. return;
});

The one change to the settings presents us with a brand-new looking chart.

See the Pen Multi Bar NVD3.JS by Danny Englishby (@DanEnglishby) on CodePen.

Using one code set with minimal changes, you just created two epic charts for the price of one. Kudos for you!

There is one last setting, of course, if you want the functionality of switching charts. Change the .showControls to true and remove the .stacked option. You will notice some controls at the top of the chart. Clicking them will toggle the view between a stacked and standard chart.

See the Pen Multi Bar Switchable NVD3.JS by Danny Englishby (@DanEnglishby) on CodePen.

Making a dashboard

There’s nothing I love looking at more in the world of web development than dashboards. They never get old and are super good looking. By using the charting techniques we’ve already covered, we can make our own responsive dashboard on a single webpage.

If you remember within the JavaScript snippets earlier, there was a function set with a listener against each chart: nv.utils.windowResize(chart.update);

This magical function, resizes the chart for you as if it was set to width: 100% in CSS. But it doesn’t just shrink, but also moves and restructures the graph according to the size of the screen. It’s pretty awesome! All we need to worry about it are the heights. We can set this up by applying flexbox to the classes assigned to chart elements.

Let’s bundle everything we have so far into one dashboard by wrapping each chart element in a flexbox container. Apply a small amount of CSS for the flexing and height, and finally, compile all the scripts into one (or, you can keep them separate in your own project).

See the Pen Dashboard NVD3.JS by Danny Englishby (@DanEnglishby) on CodePen.

Summary

This tutorial will hopefully give you the knowledge to get started with building data visualizations and, ultimately, add them into a production dashboard. Even if you only want to play with these concepts, I’m sure your mind will start running with ideas for how to transform different types of data into stunning visuals.

The post How to make a modern dashboard with NVD3.js appeared first on CSS-Tricks.

Automate Your Workflow with Node

You know those tedious tasks you have to do at work: Updating configuration files, copying and pasting files, updating Jira tickets.

Time adds up after a while. This was very much the case when I worked for an online games company back in 2016. The job could be very rewarding at times when I had to build configurable templates for games, but about 70% of my time was spent on making copies of those templates and deploying re-skinned implementations.

What is a reskin?

The definition of a reskin at the company was using the same game mechanics, screens and positioning of elements, but changing the visual aesthetics such as color and assets. So in the context of a simple game like ‘Rock Paper Scissors,’ we would create a template with basic assets like below.

But when we create a reskin of this, we would use different assets and the game would still work. If you look at games like Candy Crush or Angry Birds, you’ll find that they have many varieties of the same game. Usually Halloween, Christmas or Easter releases. From a business perspective it makes perfect sense.

Now… back to our implementation. Each of our games would share the same bundled JavaScript file, and load in a JSON file that had different content and asset paths. The result?

The good thing about extracting configurable values into a JSON file is that you can modify the properties without having to recompile/build the game again. Using Node.js and the original breakout game created by Mozilla, we will make a very simple example of how you can create a configurable template, and make releases from it by using the command line.

Our game

This is the game we’ll be making. Reskins of MDN Breakout, based on the existing source code.

Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.

The primary color will paint the text, paddle, ball and blocks, and the secondary color will paint the background. We will proceed with an example of a dark blue background and a light sky blue for the foreground objects.

Prerequisites

You will need to ensure the following:

  • You have Git installed – https://git-scm.com/downloads
  • You have Node installed – https://nodejs.org/en/download
  • You have a GitHub account – https://github.com
  • You have cloned the repository locally – https://github.com/smks/nobot-examples.git
  • You have ran npm install in the root of the nobot-examples project.
  • Finally, you run the local server by running npm run gameServe in the root of the project via a terminal.

We have tweaked the original Firefox implementation so that we first read in the JSON file and then build the game using HTML Canvas. The game will read in a primary color, and a secondary color from our game.json file.

{ "primaryColor": "#fff", "secondaryColor": "#000"
}

We will be using example 20 from the book Automating with Node.js. The source code can be found here.

Open up a new command line (CMD for Windows, Terminal for Unix-like Operating systems) and change into the following directory once you have cloned the repository locally.

$ cd nobot-examples/examples/020

Remember the game server should be running in a separate terminal.

Our JSON file sits beside an index.html file inside a directory called template. This is the directory that we will copy from whenever we want to do a new release/copy.

<!DOCTYPE html>
<html>
<head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Paddle Game</title> <style> * { padding: 0; margin: 0; } canvas { background: #eee; display: block; margin: 0 auto; } </style>
</head>
<body> <canvas id="game" width="480" height="320"></canvas> <script type="text/javascript" src="../../core/game-1.0.0.js"></script>
</body>
</html>

You see above that every game we release will point to the same core bundle JavaScript file. Let’s have a look at our JavaScript implementation under the core directory.

Don’t look too much into the mechanics of how the game works, more so how we inject values into the game to make it configurable.

(function boot(document) { function runGame(config) { const canvas = document.getElementById('game'); canvas.style.backgroundColor = config.secondaryColor; // rest of game source code gets executed... hidden for brevity // source can be found here: https://git.io/vh1Te } function loadConfig() { fetch('game.json') .then(response => response.json()) .then(runGame); } document.addEventListener('DOMContentLoaded', () => { loadConfig(); });
}(document));

The source code is using ES6 features and may not work in older browsers. Run through Babel if this is a problem for you.

You can see that we are waiting for the DOM content to load, and then we are invoking a method called loadConfig. This is going to make an AJAX request to game.json, fetch our JSON values, and once it has retrieved them, it will initiate the game and assign the styles in the source code.

Here is an example of the configuration setting the background color.

const canvas = document.getElementById('game');
canvas.style.backgroundColor = config.secondaryColor; // overriding color here

So, now that we have a template that can be configurable, we can move on to creating a Node.js script that will allow the user to either pass the name of the game and the colors as options to our new script, or will prompt the user for: the name of the game, the primary color, and then the secondary color. Our script will enforce validation to make sure that both colors are in the format of a hex code (e.g. #101b6b).

When we want to create a new game reskin, we should be able to run this command to generate it:

$ node new-reskin.js --gameName='blue-reskin' --gamePrimaryColor='#76cad8' --gameSecondaryColor='#10496b'

The command above will build the game immediately, because it has the three values it needs to release the reskin.

We will create this script new-reskin.js, and this file carries out the following steps:

  1. It will read in the options passed in the command line and store them as variables. Options can be read in by looking in the process object (process.argv).
  2. It will validate the values making sure that the game name, and the colors are not undefined.
  3. If there are any validation issues, it will prompt the user to re-enter it correctly before proceeding.
  4. Now that it has the values, it will make a copy of the template directory and place a copy of it into the releases directory and name the new directory with the name of the game we gave it.
  5. It will then read the JSON file just recently created under the releases directory and override the values with the values we passed (the colors).
  6. At the end, it will prompt the user to see if they would like to open the game in a browser. It adds some convenience, rather than us trying to remember what the URL is.

Here is the full script. We will walk through it afterwards.

require('colors');
const argv = require('minimist')(process.argv.slice(2));
const path = require('path');
const readLineSync = require('readline-sync');
const fse = require('fs-extra');
const open = require('opn');
const GAME_JSON_FILENAME = 'game.json'; let { gameName, gamePrimaryColor, gameSecondaryColor } = argv; if (gameName === undefined) { gameName = readLineSync.question('What is the name of the new reskin? ', { limit: input => input.trim().length > 0, limitMessage: 'The project has to have a name, try again' });
} const confirmColorInput = (color, colorType = 'primary') => { const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; if (hexColorRegex.test(color)) { return color; } return readLineSync.question(`Enter a Hex Code for the game ${colorType} color `, { limit: hexColorRegex, limitMessage: 'Enter a valid hex code: #efefef' });
}; gamePrimaryColor = confirmColorInput(gamePrimaryColor, 'primary');
gameSecondaryColor = confirmColorInput(gameSecondaryColor, 'secondary'); console.log(`Creating a new reskin '${gameName}' with skin color: Primary: '${gamePrimaryColor}' Secondary: '${gameSecondaryColor}'`); const src = path.join(__dirname, 'template');
const destination = path.join(__dirname, 'releases', gameName);
const configurationFilePath = path.join(destination, GAME_JSON_FILENAME);
const projectToOpen = path.join('http://localhost:8080', 'releases', gameName, 'index.html'); fse.copy(src, destination) .then(() => { console.log(`Successfully created ${destination}`.green); return fse.readJson(configurationFilePath); }) .then((config) => { const newConfig = config; newConfig.primaryColor = gamePrimaryColor; newConfig.secondaryColor = gameSecondaryColor; return fse.writeJson(configurationFilePath, newConfig); }) .then(() => { console.log(`Updated configuration file ${configurationFilePath}`green); openGameIfAgreed(projectToOpen); }) .catch(console.error); const openGameIfAgreed = (fileToOpen) => { const isOpeningGame = readLineSync.keyInYN('Would you like to open the game? '); if (isOpeningGame) { open(fileToOpen); }
};

At the top of the script, we require the packages needed to carry out the process.

  • colors to be used to signify success or failure using green or red text.
  • minimist to make it easier to pass arguments to our script and to parse them optionally. Pass input without being prompted to enter.
  • path to construct paths to the template and the destination of the new game.
  • readline-sync to prompt user for information if it’s missing.
  • fs-extra so we can copy and paste our game template. An extension of the native fs module.
  • opn is a library that is cross platform and will open up our game in a browser upon completion.

The majority of the modules above would’ve been downloaded/installed when you ran npm install in the root of the nobot-examples repository. The rest are native to Node.

We check if the game name was passed as an option through the command line, and if it hasn’t been, we prompt the user for it.

// name of our JSON file. We store it as a constant
const GAME_JSON_FILENAME = 'game.json'; // Retrieved from the command line --gameName='my-game' etc.
let { gameName, gamePrimaryColor, gameSecondaryColor } = argv; // was the gameName passed?
if (gameName === undefined) { gameName = readLineSync.question('What is the name of the new reskin? ', { limit: input => input.trim().length > 0, limitMessage: 'The project has to have a name, try again' });
}

Because two of our values need to be hex codes, we create a function that can do the check for both colors: the primary and the secondary. If the color supplied by the user does not pass our validation, we prompt for the color until it does.

// Does the color passed in meet our validation requirements?
const confirmColorInput = (color, colorType = 'primary') => { const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; if (hexColorRegex.test(color)) { return color; } return readLineSync.question(`Enter a Hex Code for the game ${colorType} color `, { limit: hexColorRegex, limitMessage: 'Enter a valid hex code: #efefef' });
};

We use the function above to obtain both the primary and secondary colors.

gamePrimaryColor = confirmColorInput(gamePrimaryColor, 'primary');
gameSecondaryColor = confirmColorInput(gameSecondaryColor, 'secondary');

In the next block of code, we are printing to standard output (console.log) to confirm the values that will be used in the process of building the game. The statements that follow are preparing the paths to the relevant files and directories.

The src will point to the template directory. The destination will point to a new directory under releases. The configuration file that will have its values updated will reside under this new game directory we are creating. And finally, to preview our new game, we construct the URL using the path to the local server we booted up earlier on.

console.log(`Creating a new reskin '${gameName}' with skin color: Primary: '${gamePrimaryColor}' Secondary: '${gameSecondaryColor}'`);
const src = path.join(__dirname, 'template');
const destination = path.join(__dirname, 'releases', gameName);
const configurationFilePath = path.join(destination, GAME_JSON_FILENAME);
const projectToOpen = path.join('http://localhost:8080', 'releases', gameName, 'index.html');

In the code following this explanation, we:

  • Copy the template files to the releases directory.
  • After this is created, we read the JSON of the original template values.
  • With the new configuration object, we override the existing primary and secondary colors provided by the user’s input.
  • We rewrite the JSON file so it has the new values.
  • When the JSON file has been updated, we ask the user if they would like to open the new game in a browser.
  • If anything went wrong, we catch the error and log it out.
fse.copy(src, destination) .then(() => { console.log(`Successfully created ${destination}`green); return fse.readJson(configurationFilePath); }) .then((config) => { const newConfig = config; newConfig.primaryColor = gamePrimaryColor; newConfig.secondaryColor = gameSecondaryColor; return fse.writeJson(configurationFilePath, newConfig); }) .then(() => { console.log(`Updated configuration file ${configurationFilePath}`green); openGameIfAgreed(projectToOpen); }) .catch(console.error);

Below is the function that gets invoked when the copying has completed. It will then prompt the user to see if they would like to open up the game in the browser. The user responds with y or n

const openGameIfAgreed = (fileToOpen) => { const isOpeningGame = readLineSync.keyInYN('Would you like to open the game? '); if (isOpeningGame) { open(fileToOpen); }
};

Let’s see it in action when we don’t pass any arguments. You can see it doesn’t break, and instead prompts the user for the values it needs.

$ node new-reskin.js
What is the name of the new reskin? blue-reskin
Enter a Hex Code for the game primary color #76cad8
Enter a Hex Code for the game secondary color #10496b
Creating a new reskin 'blue-reskin' with skin color: Primary: '#76cad8' Secondary: '#10496b'
Successfully created nobot-examples\examples\020\releases\blue-reskin
Updated configuration file nobot-examples\examples\020\releases\blue-reskin\game.json
Would you like to open the game? [y/n]: y
(opens game in browser)

My game opens on my localhost server automatically and the game commences, with the new colors. Sweet!

Oh… I’ve lost a life already. Now if you navigate to the releases directory, you will see a new directory called blue-reskin This contains the values in the JSON file we entered during the script execution.

Below are a few more releases I made by running the same command. You can imagine if you were releasing games that could configure different: images, sounds, labels, content and fonts, you would have a rich library of games based on the same mechanics.

Even better, if the stakeholders and designers had all of this information in a Jira ticket, you could integrate the Jira API into the Node script to inject these values in without the user having to provide any input. Winning!


This is one of many examples that can be found in Automating with Node.js. In this book, we will be looking at a more advanced example using “Rock Paper Scissors” as the basis of a build tool created from scratch.

  • Color Print: http://amzn.eu/aA0cSnu
  • Kindle: https://amzn.to/2JPTk7q
  • Kobo: https://www.kobo.com/gb/en/ebook/automating-with-node-js
  • Leanpub: https://leanpub.com/automatingwithnodejs

The post Automate Your Workflow with Node appeared first on CSS-Tricks.

CSS-in-JS: FTW || WTF?

I enjoyed Bruce Lawson’s talk on this holiest of wars. It’s funny and lighthearted while being well researched and fairly portraying the good arguments on both sides.

The post CSS-in-JS: FTW || WTF? appeared first on CSS-Tricks.

Render Children in React Using Fragment or Array Components

What comes to your mind when React 16 comes up? Context? Error Boundary? Those are on point. React 16 came with those goodies and much more, but In this post, we’ll be looking at the rendering power it also introduced — namely, the ability to render children using Fragments and Array Components.

These are new and really exciting concepts that came out of the React 16 release, so let’s look at them closer and get to know them.

Fragments

It used to be that React components could only return a single element. If you have ever tried to return more than one element, you know that you’ll will be greeted with this error: Syntax error: Adjacent JSX elements must be wrapped in an enclosing tag. The way out of that is to make use of a wrapper div or span element that acts as the enclosing tag.

So instead of doing this:

class Countries extends React.Component { render() { return ( <li>Canada</li> <li>Australia</li> <li>Norway</li> <li>Mexico</li> ) }
}

…you have to add either an ol or ul tag as a wrapper on those list items:

class Countries extends React.Component { render() { return ( <ul> <li>Canada</li> <li>Australia</li> <li>Norway</li> <li>Mexico</li> </ul> ) }
}

Most times, this may not be the initial design you had for the application, but you are left with no choice but to compromise on this ground.

React 16 solves this with Fragments. This new features allows you to wrap a list of children without adding an extra node. So, instead of adding an additional element as a wrapper like we did in the last example, we can throw <React.Fragment> in there to do the job:

class Countries extends React.Component { render() { return ( <React.Fragment> <li>Canada</li> <li>Australia</li> <li>Norway</li> <li>Mexico</li> </React.Fragment> ) }
}

You may think that doesn’t make much difference. But, imagine a situation where you have a component that lists different items such as fruits and other things. These items are all components, and if you are making use of old React versions, the items in these individual components will have to be wrapped in an enclosing tag. Now, however, you can make use of fragments and do away with that unnecessary markup.

Here’s a sample of what I mean:

class Items extends React.Component { render() { return ( <React.Fragment> <Fruit /> <Beverages /> <Drinks /> </React.Fragment> ) }
}

We have three child components inside of the fragment and can now create a component for the container that wraps it. This is much more in line with being able to create components out of everything and being able to compile code with less cruft.

Fragment Shorthand

There is a shorthand syntax when working with Fragments, which you can use. Staying true to its fragment nature, the syntax is like a fragment itself, leaving only only empty brackets behind.

Going back to our last example:

class Fruit extends React.Component { render() { return ( <> <li>Apple</li> <li>Orange</li> <li>Blueberry</li> <li>Cherry</li> </> ) }
}

Question: Is a fragment better than a container div?

You may be looking for a good reason to use Fragments instead of the container div you have always been using. Dan Abramov answered the question on StackOverflow. To summarize:

  1. It’s a tiny bit faster and has less memory usage (no need to create an extra DOM node). This only has a real benefit on very large and/or deep trees, but application performance often suffers from death by a thousand cuts. This is one less cut.
  2. Some CSS mechanisms like flexbox and grid have a special parent-child relationship, and adding divs in the middle makes it harder to maintain the design while extracting logical components.
  3. The DOM inspector is less cluttered.

Keys in Fragments

When mapping a list of items, you still need to make use of keys the same way as before. For example, let’s say we want to pass a list of items as props from a parent component to a child component. In the child component, we want to map through the list of items we have and output each item as a separate entity. Here’s how that looks:

const preload = { "data" : [ { "name": "Reactjs", "url": "https://reactjs.org", "description": "A JavaScript library for building user interfaces", }, { "name": "Vuejs", "url": "https://vuejs.org", "description": "The Progressive JavaScript Framework", }, { "name": "Emberjs", "url": "https://www.emberjs.com", "description": "Ember.js is an open-source JavaScript web framework, based on the Model–view–viewmodel pattern" } ]
} const Frameworks = (props) => { return ( <React.Fragment> {props.items.data.map(item => ( <React.Fragment key={item.id}> <h2>{item.name}</h2> <p>{item.url}</p> <p>{item.description}</p> </React.Fragment> ))} </React.Fragment> )
} const App = () => { return ( <Frameworks items={preload} /> )
}

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

You can see that now, in this case, we are not making use of any divs in the Frameworks component. That’s the key difference!

Render Children Using an Array of Components

The second specific thing that came out of React 16 we want to look at is the ability to render multiple children using an array of components. This is a clear timesaver because it allows us to cram as many into a render instead of having to do it one-by-one.

Here is an example:

class Frameworks extends React.Component { render () { return ( [ <p>JavaScript:</p> <li>React</li>, <li>Vuejs</li>, <li>Angular</li> ] ) }
}

You can also do the same with a stateless functional component:

const Frontend = () => { return [ <h3>Front-End:</h3>, <li>Reactjs</li>, <li>Vuejs</li> ]
} const Backend = () => { return [ <h3>Back-End:</h3>, <li>Express</li>, <li>Restify</li> ]
} const App = () => { return [ <h2>JavaScript Tools</h2>, <Frontend />, <Backend /> ]
}

See the Pen React Fragment 2 Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Conclusion

Like the Context API and Error Boundary feature that were introduced in React 16, rendering children components with Fragment and multiples of them with Array Components are two more awesome features you can start making use of as you build your application.

Have you started using these in a project? Let me know how in the comments so we can compare notes. 🙂

The post Render Children in React Using Fragment or Array Components appeared first on CSS-Tricks.

PSA: Yes, Serverless Still Involves Servers.

You clever dog. You’ve rooted it out! It turns out when you build things with serverless technology you’re still using servers. Pardon the patronizing tone there, I’ve seen one-too-many hot takes at this point where someone points this fact out and trots away triumphantly.

And yes, because serverless still involves servers, the term might be a bit disingenuous to some. You could be forgiven for thinking that serverless meant technologies like web workers, which use the client to do things you might have otherwise done on a server and is where the term serverless was headed. Alas, it is not.

What serverless really means:

  • Using other people’s servers instead of running your own. You’re probably already doing that, but serverless takes it to another level where you have no control over the server outside of telling it to run a bit of code.
  • You don’t need to think about scaling — that’s the serverless provider’s problem.
  • You are only paying per execution of your code and not some fixed cost per time.
  • You only worry about your code being misused, but not the security of the server itself.
  • We’re mostly talking about Cloud Functions above, but I’d argue the serverless movement involves anything that allows you to work from static hosting and leverage services to help you with functionality. For example, even putting a Google Form on a static site is within the serverless spirit.

Serverless is about outsourcing a little bit more of your project to companies that are incentivized to do it well. My hope is that someday we can have a conversation about serverless without having to tread this ground every time and spat about the term. I suspect we will. I think we’re almost over the term the cloud as an industry and we’ll jump this hurdle too. It’s worth it when a single word successfully evokes a whole ecosystem.

Wanna know more about serverless? Here’s the tag on CSS-Trick where we’ve talked about it a bunch.

The post PSA: Yes, Serverless Still Involves Servers. appeared first on CSS-Tricks.

Create your own Serverless API

If you don’t already know of it, Todd Motto has this great list of public APIs. It’s awesome if you’re trying out a new framework or new layout pattern and want to hit the ground running without fussing with the content.

But what if you want or need to make your own API? Serverless can help create a nice one for data you’d like to expose for use.

Serverless really shines for this use case, and hopefully this post makes it clear why. In a non-serverless paradigm, we have to pick something like express, we have to set up endpoints, we have to give your web server secured access to your database server, you have to deploy it, etc. In contrast, here we’ll be able to create an API in a few button clicks, with minor modifications.

Here’s the inspiration for this tutorial: I’ve been building a finder to search for new cocktails and grab random one. I originally started using ae public API but realized quickly that I found the contents limiting and wanted to shape my own.

I’m going to use Azure for these examples but it is possible to accomplish what we’re doing here with other cloud providers as well.

Make the Function

To get started, if you haven’t already, create a free Azure trial account. Then go to the portal: preview.portal.azure.com.

Next, we’ll hit the plus sign at the top left and select Serverless Function App from the list. We can then fill in the new name of our function and some options. It will pick up our resource group, subscription, and create a storage account from defaults. It will also use the location data from the resource group. So, happily, it’s pretty easy to populate the data.

Next, we’ll create a new function using HTTP Trigger, and go to the Integrate tab to perform some actions:

What we did was:

  • Give the route template a name
  • Change the authorization level to “Anonymous”
  • Change the allowed HTTP methods to “Selected Method”
  • Select “GET” for the selected method and unchecked everything else

Now, if we get the function URL from the top right of our function, we’ll get this:

https://sdras-api-demo.azurewebsites.net/api/hello

The initial boilerplate testing code that we’re given is:

module.exports = function (context, req) { context.log('JavaScript HTTP trigger function processed a request.'); if (req.query.name || (req.body && req.body.name)) { context.res = { // status: 200, /* Defaults to 200 */ body: "Hello " + (req.query.name || req.body.name) }; } else { context.res = { status: 400, body: "Please pass a name on the query string or in the request body" }; } context.done();
};

Now if we go to the URL below, we’ll see this:

https://sdras-api-demo.azurewebsites.net/api/hello/?name=TacoFace
Says hello TacoFace

There’s more information in this blog post, including API unification with Function Proxies. You can also use custom domains, not covered here.

OK, now that that initial part is all set up, let’s find a place to host our data.

Storing the data with CosmosDB

There are a number of ways to store the data for our function. I wanted to use Cosmos because it has one-click integration, making for a pretty low-friction choice. Get a free account here. Once you’re in the portal, we’ll go to the plus sign in the top left to create a new service and this time select “CosmosDB.” In this case, we chose the SQL version.

We have a few options for how to create our documents in the database. We’re merely making a small example for demo purposes, so we can manually create them by going to Data Explorer in the sidebar. In there, I made a database called CocktailFinder, a collection called Cocktails, and added each document. For our Partition Key, we’ll use /id.

creating a collection

In real practice, you’d probably either want to upload a JSON file by clicking the “Upload JSON” button or follow this article for how to create the files with the CLI.

We can add something in JSON format like this:

{ "id": "1", "drink": "gin_and_tonic", "ingredients": [ "2 ounces gin", "2 lime wedges", "3–4 ounces tonic water" ], "directions": "Add gin to a highball glass filled with ice. Squeeze in lime wedges to taste, then add them to glass. Add tonic water; stir to combine.", "glass": [ "highball", "hurricane" ], "image": "https://images.unsplash.com/photo-1523905491727-d82018a34d75?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=52731e6d008be93fda7f5af1145eac12&auto=format&fit=crop&w=750&q=80"
}

And here is the example with all three that we’ve created, and what Cosmos adds in:

Have the function surface the data

OK, now we’ve got some dummy data to work with, so let’s connect it to our serverless function so we can finish up our API!

If we go back to our function in the portal and click Integrate in the sidebar again, there’s a middle column that called Inputs. Here, we can click on the plus that says “+ New Inputs” and a few options come up. We’ll click the CosmosDB option and “Create.”

Showing in the portal the button to create a connection with CosmosDB

A prompt will come up that asks us to provide information about our Database and Collection. If you recall, the databaseName was CocktailFinder and the collectionName was Cocktails. We also want to use the same partitionKey which was /id. We’ll use all the other defaults.

Now if we go to our function.jso, you can see that it’s now been updated with:

{ "type": "documentDB", "name": "inputDocument", "databaseName": "CocktailFinder", "collectionName": "Cocktails", "partitionKey": "/id", "connection": "sdrassample_DOCUMENTDB", "direction": "in"
}

We’re going to use that inputDocument to update our testing function to reflect that’s what we’re trying to access. I also add in the status and log frequently, but that’s optional.

module.exports = function (context, req) { context.log('JavaScript HTTP trigger function processed a request.'); if (context.bindings) { context.log('Get ready'); context.res = {status: 200, body: context.bindings.inputDocument}; context.log(context.res); } else { context.res = { status: 400, body: "Something went wrong" }; } context.done();
};

Now you can see our function at work!

CORS!

Can’t forget the axios call. I have a really barebones CodePen implementation so that you can see how that might work. In Vue, we’re hooking into the created lifecycle method and making the GET request, in order to output the JSON data to the page.

See the Pen Show API Output, beginning of Vue.js integration by Sarah Drasner (@sdras) on CodePen.

From here, you have all that data to play with, and you can store whatever you like in whatever form you fancy. You can use something like Vue, React, or Angular to create interfaces with the content we stored in our database, and our serverless function creates the API for us. The sky is the limit to what we can create! 🎉

The post Create your own Serverless API appeared first on CSS-Tricks.