An Illustrated (and Musical) Guide to Map, Reduce, and Filter Array Methods

Map, reduce, and filter are three very useful array methods in JavaScript that give developers a ton of power in a short amount of space. Let’s jump right into how you can leverage (and remember how to use!) these super handy methods.

Array.map()

Array.map() updates each individual value in a given array based on a provided transformation and returns a new array of the same size. It accepts a callback function as an argument, which it uses to apply the transform.

let newArray = oldArray.map((value, index, array) => { ...
});

A mnemonic to remember this is MAP: Morph Array Piece-by-Piece.

Instead of a for-each loop to go through and apply this transformation to each value, you can use a map. This works when you want to preserve each value, but update it. We’re not potentially eliminating any values (like we would with a filter), or calculating a new output (like we would use reduce for). A map lets you morph an array piece-by-piece. Let’s take a look at an example:

[1, 4, 6, 14, 32, 78].map(val => val * 10)
// the result is: [10, 40, 60, 140, 320, 780]

In the above example, we take an initial array ([1, 4, 6, 14, 32, 78]) and map each value in it to be that value times ten (val * 10). The result is a new array with each value of the original array transformed by the equation: [10, 40, 60, 140, 320, 780].

An illustration of the code examples covered in this section.

Array.filter()

Array.filter() is a very handy shortcut when we have an array of values and want to filter those values into another array, where each value in the new array is a value that passes a specific test.

This works like a search filter. We’re filtering out values that pass the parameters we provide.

For example, if we have an array of numeric values, and want to filter them to just the values that are larger than 10, we could write:

[1, 4, 6, 14, 32, 78].filter(val => val > 10)
// the result is: [14, 32, 78]

If we were to use a map method on this array, such as in the example above, we would return an array of the same length as the original with val > 10 being the “transform,” or a test in this case. We transform each of the original values to their answer if they are greater than 10. It would look like this:

[1, 4, 6, 14, 32, 78].map(val => val > 10)
// the result is: [false, false, false, true, true, true]

A filter, however, returns only the true values. So the result is smaller than the original array or the same size if all values pass a specific test.

Think about filter like a strainer-type-of-filter. Some of the mix will pass through into the result, but some will be left behind and discarded.

An illustration of a funnel with numbers going in the top and a few coming out of the bottom next to a handwritten version of the code covered in this section.

Say we have a (very small) class of four dogs in obedience school. All of the dogs had challenges throughout obedience school and took a graded final exam. We’ll represent the doggies as an array of objects, i.e.:

const students = [ { name: "Boops", finalGrade: 80 }, { name: "Kitten", finalGrade: 45 }, { name: "Taco", finalGrade: 100 }, { name: "Lucy", finalGrade: 60 }
]

If the dogs get a score higher than 70 on their final test, they get a fancy certificate; and if they don’t, they’ll need to take the course again. In order to know how many certificates to print, we need to write a method that will return the dogs with passing grades. Instead of writing out a loop to test each object in the array, we can shorten our code with filter!

const passingDogs = students.filter((student) => { return student.finalGrade >= 70
}) /*
passingDogs = [ { name: "Boops", finalGrade: 80 }, { name: "Taco", finalGrade: 100 }
]
*/

As you can see, Boops and Taco are good dogs (actually, all dogs are good dogs), so Boops and Taco are getting certificates of achievement for passing the course! We can write this in a single line of code with our lovely implicit returns and then remove the parenthesis from our arrow function since we have single argument:

const passingDogs = students.filter(student => student.finalGrade >= 70) /*
passingDogs = [ { name: "Boops", finalGrade: 80 }, { name: "Taco", finalGrade: 100 }
]
*/

Array.reduce()

The reduce() method takes the input values of an array and returns a single value. This one is really interesting. Reduce accepts a callback function which consists of an accumulator (a value that accumulates each piece of the array, growing like a snowball), the value itself, and the index. It also takes a starting value as a second argument:

let finalVal = oldArray.reduce((accumulator, currentValue, currentIndex, array) => { ...
}), initalValue;
An illustration of a saucepan cooking ingredients next to handwritten code from the examples covered in this section.

Let’s set up a cook function and a list of ingredients:

// our list of ingredients in an array
const ingredients = ['wine', 'tomato', 'onion', 'mushroom'] // a cooking function
const cook = (ingredient) => { return `cooked ${ingredient}`
}

If we want to reduce the items into a sauce (pun absolutely intended), we’ll reduce them with reduce()!

const wineReduction = ingredients.reduce((sauce, item) => { return sauce += cook(item) + ', ' }, '') // wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom, "

That initial value ('' in our case) is important because if we don’t have it, we don’t cook the first item. It makes our output a little wonky, so it’s definitely something to watch out for. Here’s what I mean:

const wineReduction = ingredients.reduce((sauce, item) => { return sauce += cook(item) + ', ' }) // wineReduction = "winecooked tomato, cooked onion, cooked mushroom, "

Finally, to make sure we don’t have any excess spaces at the end of our new string, we can pass in the index and the array to apply our transformation:

const wineReduction = ingredients.reduce((sauce, item, index, array) => { sauce += cook(item) if (index < array.length - 1) { sauce += ', ' } return sauce }, '') // wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom"

Now we can write this even more concisely (in a single line!) using ternary operators, string templates, and implicit returns:

const wineReduction = ingredients.reduce((sauce, item, index, array) => { return (index < array.length - 1) ? sauce += `${cook(item)}, ` : sauce += `${cook(item)}`
}, '') // wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom"

A little way to remember this is to recall how you make sauce: you reduce a few ingredients down to a single item.

Sing it with me!

I wanted to end this blog post with a song, so I wrote a little diddy about array methods that might just help you to remember them:

The post An Illustrated (and Musical) Guide to Map, Reduce, and Filter Array Methods appeared first on CSS-Tricks.

Buddy: 15 Minutes to Automation Nirvana

(This is a sponsored post.)

Deploying a website to the server in 2019 requires much more effort than 10 years ago. For example, here’s what needs to be done nowadays to deliver a typical JS app:

  • split the app into chunks
  • configure webpack bundle
  • minify .js files
  • set up staging environment
  • upload the files to the server

Running these steps manually takes time, so an automation tool seems like an obvious choice. Unfortunately, most of contemporary CI/CD software provide nothing more than infrastructure in which you have to manually configure the process anyway: spend hours reading the documentation, writing scripts, testing the outcome, and maintaining it later on. Ain’t nobody got time for that!

This is why we created Buddy: to simplify deployment to the absolute minimum by creating a robust tool whose UI/UX allows you configure the whole process in 15 minutes.

Here’s how the delivery process looks in Buddy CI/CD:

This is a delivery pipeline in Buddy. You select the action that you need, configure the details, and put it down in place—just like you’re building a house of bricks. No scripting, no documentation, no nothing. Currently, Buddy supports over 100 actions: builds, tests, deployments, notifications, DevOps tools & many more.

Super-Smooth Deployments

Buddy’s deployments are based on changesets which means only changed files are deployed – there’s no need to upload the whole repository every time.

Configuration is very simple. For example, in order to deploy to SFTP, you just need to enter authentication details and the target path on the server:

Buddy supports deployments to all popular stacks, PaaS, and IaaS services, including AWS, Google Cloud, Microsoft Azure, and DigitalOcean. Here’s a small part of the supported integrations:

Faster Builds, Better Apps

Builds are run in isolated containers with a preconfigured dev environment. Dependencies and packages are downloaded on the first execution and cached in the container, which massively improves build performance.

Buddy supports all popular web developer languages and frameworks, including Node.js, PHP, Ruby, WordPress, Python, .NET Core and Go:

Docker for the People

Being a Docker-based tool itself, Buddy helps developers embrace the power of containers with a dedicated roster of Docker actions. You can build custom images and use them in your builds, run dockerized apps on a remote, and easily orchestrate containers on a Kubernetes cluster.

Buddy has dedicated integrations with Google GKE, Amazon EKS, and Azure AKS. You can also push and images to and from private registries.

Automate now!

Sign up to Buddy now and get 5 projects forever free when your trial is over. The process is simple: click the button below, hook up your GitHub, Bitbucket or GitLab repository (or any other), and let Buddy carry you on from there. See you onboard!

Create free account

Direct Link to ArticlePermalink

The post Buddy: 15 Minutes to Automation Nirvana appeared first on CSS-Tricks.

Understanding Event Emitters

Consider, a DOM Event:

const button = document.querySelector("button"); button.addEventListener("click", (event) => /* do something with the event */)

We added a listener to a button click. We’ve subscribed to an event being emitted and we fire a callback when it does. Every time we click that button, that event is emitted and our callback fires with the event.

There may be times you want to fire a custom event when you’re working in an existing codebase. Not specifically a DOM event like clicking a button, but let’s say you want to emit an event based on some other trigger and have an event respond. We need a custom event emitter to do that.

An event emitter is a pattern that listens to a named event, fires a callback, then emits that event with a value. Sometimes this is referred to as a “pub/sub” model, or listener. It’s referring to the same thing.

In JavaScript, an implementation of it might work like this:

let n = 0;
const event = new EventEmitter(); event.subscribe("THUNDER_ON_THE_MOUNTAIN", value => (n = value)); event.emit("THUNDER_ON_THE_MOUNTAIN", 18); // n: 18 event.emit("THUNDER_ON_THE_MOUNTAIN", 5); // n: 5

In this example, we’ve subscribed to an event called “THUNDER_ON_THE_MOUNTAIN” and when that event is emitted our callback value => (n = value) will be fired. To emit that event, we call emit().

This is useful when working with async code and a value needs to be updated somewhere that isn’t co-located with the current module.

A really macro-level example of this is React Redux. Redux needs a way to externally share that its internal store has updated so that React knows those values have changed, allowing it to call setState() and re-render the UI. This happens through an event emitter. The Redux store has a subscribe function, and it takes a callback that provides the new store and, in that function, calls React Redux’s <Provider> component, which calls setState() with the new store value. You can look through the whole implementation here.

Now we have two different parts of our application: the React UI and the Redux store. Neither one can tell the other about events that have been fired.

Implementation

Let’s look at building a simple event emitter. We’ll use a class, and in that class, track the events:

class EventEmitter { public events: Events; constructor(events?: Events) { this.events = events || {}; }
}

Events

We’ll define our events interface. We will store a plain object, where each key will be the named event and its respective value being an array of the callback functions.

interface Events { [key: string]: Function[];
} /**
{ "event": [fn], "event_two": [fn]
}
*/

We’re using an array because there could be more than one subscriber for each event. Imagine the number of times you’d call element.addEventLister("click") in an application… probably more than once.

Subscribe

Now we need to deal with subscribing to a named event. In our simple example, the subscribe() function takes two parameters: a name and a callback to fire.

event.subscribe("named event", value => value);

Let’s define that method so our class can take those two parameters. All we’ll do with those values is attach them to the this.events we’re tracking internally in our class.

class EventEmitter { public events: Events; constructor(events?: Events) { this.events = events || {}; } public subscribe(name: string, cb: Function) { (this.events[name] || (this.events[name] = [])).push(cb); }
}

Emit

Now we can subscribe to events. Next up, we need to fire those callbacks when a new event emits. When it happen, we’ll use event name we’re storing (emit("event")) and any value we want to pass with the callback (emit("event", value)). Honestly, we don’t want to assume anything about those values. We’ll simply pass any parameter to the callback after the first one.

class EventEmitter { public events: Events; constructor(events?: Events) { this.events = events || {}; } public subscribe(name: string, cb: Function) { (this.events[name] || (this.events[name] = [])).push(cb); } public emit(name: string, ...args: any[]): void { (this.events[name] || []).forEach(fn => fn(...args)); }
}

Since we know which event we’re looking to emit, we can look it up using JavaScript’s object bracket syntax (i.e. this.events[name]). This gives us the array of callbacks that have been stored so we can iterate through each one and apply all of the values we’re passing along.

Unsubscribing

We’ve got the main pieces solved so far. We can subscribe to an event and emit that event. That’s the big stuff.

Now we need to be able to unsubscribe from an event.

We already have the name of the event and the callback in the subscribe() function. Since we could have many subscribers to any one event, we’ll want to remove callbacks individually:

subscribe(name: string, cb: Function) { (this.events[name] || (this.events[name] = [])).push(cb); return { unsubscribe: () => this.events[name] && this.events[name].splice(this.events[name].indexOf(cb) >>> 0, 1) };
}

This returns an object with an unsubscribe method. We use an arrow function (() =>) to get the scope of this parameters that are passed to the parent of the object. In this function, we’ll find the index of the callback we passed to the parent and use the bitwise operator (>>>). The bitwise operator has a long and complicated history (which you can read all about). Using one here ensures we’ll always get a real number every time we call splice() on our array of callbacks, even if indexOf() doesn’t return a number.

Anyway, it’s available to us and we can use it like this:

const subscription = event.subscribe("event", value => value); subscription.unsubscribe();

Now we’re out of that particular subscription while all other subscriptions can keep chugging along.

All Together Now!

Sometimes it helps to put all the little pieces we’ve discussed together to see how they relate to one another.

interface Events { [key: string]: Function[];
} export class EventEmitter { public events: Events; constructor(events?: Events) { this.events = events || {}; } public subscribe(name: string, cb: Function) { (this.events[name] || (this.events[name] = [])).push(cb); return { unsubscribe: () => this.events[name] && this.events[name].splice(this.events[name].indexOf(cb) >>> 0, 1) }; } public emit(name: string, ...args: any[]): void { (this.events[name] || []).forEach(fn => fn(...args)); }
}

Demo

See the Pen
Understanding Event Emitters
by Charles (@charliewilco)
on CodePen.

We’re doing a few thing in this example. First, we’re using an event emitter in another event callback. In this case, an event emitter is being used to clean up some logic. We’re selecting a repository on GitHub, fetching details about it, caching those details, and updating the DOM to reflect those details. Instead of putting that all in one place, we’re fetching a result in the subscription callback from the network or the cache and updating the result. We’re able to do this because we’re giving the callback a random repo from the list when we emit the event

Now let’s consider something a little less contrived. Throughout an application, we might have lots of application states that are driven by whether we’re logged in and we may want multiple subscribers to handle the fact that the user is attempting to log out. Since we’ve emitted an event with false, every subscriber can use that value, and whether we need to redirect the page, remove a cookie or disable a form.

const events = new EventEmitter(); events.emit("authentication", false); events.subscribe("authentication", isLoggedIn => { buttonEl.setAttribute("disabled", !isLogged);
}); events.subscribe("authentication", isLoggedIn => { window.location.replace(!isLoggedIn ? "/login" : "");
}); events.subscribe("authentication", isLoggedIn => { !isLoggedIn && cookies.remove("auth_token");
});

Gotchas

As with anything, there are a few things to consider when putting emitters to work.

  • We need to use forEach or map in our emit() function to make sure we’re creating new subscriptions or unsubscribing from a subscription if we’re in that callback.
  • We can pass pre-defined events following our Events interface when a new instance of our EventEmitter class has been instantiated, but I haven’t really found a use case for that.
  • We don’t need to use a class for this and it’s largely a personal preference whether or not you do use one. I personally use one because it makes it very clear where events are stored.

As long as we’re speaking practicality, we could do all of this with a function:

function emitter(e?: Events) { let events: Events = e || {}; return { events, subscribe: (name: string, cb: Function) => { (events[name] || (events[name] = [])).push(cb); return { unsubscribe: () => { events[name] && events[name].splice(events[name].indexOf(cb) >>> 0, 1); } }; }, emit: (name: string, ...args: any[]) => { (events[name] || []).forEach(fn => fn(...args)); } };
}

Bottom line: a class is just a preference. Storing events in an object is also a preference. We could just as easily have worked with a Map() instead. Roll with what makes you most comfortable.


I decided to write this post for two reasons. First, I always felt I understood the concept of emitters made well, but writing one from scratch was never something I thought I could do but now I know I can — and I hope you now feel the same way! Second, emitters are make frequent appearances in job interviews. I find it really hard to talk coherently in those types of situations, and jotting it down like this makes it easier to capture the main idea and illustrate the key points.

I’ve set all this up in a GitHub repo if you want to pull the code and play with it. And, of course, hit me up with questions in the comments if anything pops up!

The post Understanding Event Emitters appeared first on CSS-Tricks.

Simple & Boring

Simplicity is a funny adjective in web design and development. I’m sure it’s a quoted goal for just about every project ever done. Nobody walks into a kickoff meeting like, “Hey team, design something complicated for me. Oh, and make sure the implementation is convoluted as well. Over-engineer that sucker, would ya?”

Of course they want simple. Everybody wants simple. We want simple designs because simple means our customers will understand it and like it. We want simplicity in development. Nobody dreams of going to work to spend all day wrapping their head around a complex system to fix one bug.

Still, there is plenty to talk about when it comes to simplicity. It would be very hard to argue that web development has gotten simpler over the years. As such, the word has lately been on the tongues of many web designers and developers. Let’s take a meandering waltz through what other people have to say about simplicity.

Bridget Stewart recalls a frustrating battle against over-engineering in “A Simpler Web: I Concur.” After being hired as an expert in UI implementation and given the task of getting a video to play on a click…

I looked under the hood and got lost in all the looping functions and the variables and couldn’t figure out what the code was supposed to do. I couldn’t find any HTML <video> being referenced. I couldn’t see where a link or a button might be generated. I was lost.

I asked him to explain what the functions were doing so I could help figure out what could be the cause, because the browser can play video without much prodding. Instead of successfully getting me to understand what he had built, he argued with me about whether or not it was even possible to do. I tried, at first calmly, to explain to him I had done it many times before in my previous job, so I was absolutely certain it could be done. As he continued to refuse my explanation, things got heated. When I was done yelling at him (not the most professional way to conduct myself, I know), I returned to my work area and fired up a branch of the repo to implement it. 20 minutes later, I had it working.

It sounds like the main problem here is that the dude was a territorial dingus, but also his complicated approach literally stood in the way of getting work done.

Simplicity on the web often times means letting the browser do things for us. How many times have you seen a complex re-engineering of a select menu not be as usable or accessible as a <select>?

Jeremy Wagner writes in Make it Boring:

Eminently usable designs and architectures result when simplicity is the default. It’s why unadorned HTML works. It beautifully solves the problem of presenting documents to the screen that we don’t even consider all the careful thought that went into the user agent stylesheets that provide its utterly boring presentation. We can take a lesson from this, especially during a time when more websites are consumed as web apps, and make them more resilient by adhering to semantics and native web technologies.

My guess is the rise of static site generators — and sites that find a way to get as much server-rendered as possible — is a symptom of the industry yearning for that brand of resilience.

Do less, as they say. Lyza Danger Gardner found a lot of value in this in her own job:

… we need to try to do as little as possible when we build the future web.

This isn’t a rationalization for laziness or shirking responsibility—those characteristics are arguably not ones you’d find in successful web devs. Nor it is a suggestion that we build bland, homogeneous sites and apps that sacrifice all nuance or spark to the Greater Good of total compatibility.

Instead it is an appeal for simplicity and elegance: putting commonality first, approaching differentiation carefully, and advocating for consistency in the creation and application of web standards.

Christopher T. Miller writes in “A Simpler Web”:

Should we find our way to something simpler, something more accessible?

I think we can. By simplifying our sites we achieve greater reach, better performance, and more reliable conveying of the information which is at the core of any website. I think we are seeing this in the uptick of passionate conversations around user experience, but it cannot stop with the UX team. Developers need to take ownership for the complexity they add to the Web.

It’s good to remember that the complexity we layer onto building websites is opt-in. We often do it for good reason, but it’s possible not to. Garrett Dimon:

You can build a robust, reliable, and fully responsive web application today using only semantic HTML on the front-end. No images. No CSS. No JavaScript. It’s entirely possible. It will work in every modern browser. It will be straightforward to maintain. It may not fit the standard definition of beauty as far as web experiences go, but it will work. In many cases, it will be more usable and accessible than those built with modern front-end frameworks.

That’s not to say that this is the best approach, but it’s a good reminder that the web works by default without all of our additional layers. When we add those additional layers, things break. Or, if we neglect good markup and CSS to begin with, we start out with something that’s already broken and then spend time trying to make it work again.

We assume that complex problems always require complex solutions. We try to solve complexity by inventing tools and technologies to address a problem; but in the process, we create another layer of complexity that, in turn, causes its own set of issues.

— Max Böck, “On Simplicity”

Perhaps the worst reason to choose a complex solution is that it’s new, and the newness makes it feel like choosing it makes you on top of technology and doing your job well. Old and boring may just what you need to do your job well.

Dan McKinley writes:

“Boring” should not be conflated with “bad.” There is technology out there that is both boring and bad. You should not use any of that. But there are many choices of technology that are boring and good, or at least good enough. MySQL is boring. Postgres is boring. PHP is boring. Python is boring. Memcached is boring. Squid is boring. Cron is boring.

The nice thing about boringness (so constrained) is that the capabilities of these things are well understood. But more importantly, their failure modes are well understood.

Rachel Andrew wrote that choosing established technology for the CMS she builds was a no-brainer because it’s what her customers had.

You’re going to hear less about old and boring technology. If you’re consuming a healthy diet of tech news, you probably won’t read many blog posts about old and boring technology. It’s too bad really, I, for one, would enjoy that. But I get it, publications need to have fresh writing and writers are less excited about topics that have been well-trod over decades.

As David DeSandro says, “New tech gets chatter”. When there is little to say, you just don’t say it.

You don’t hear about TextMate because TextMate is old. What would I tweet? Still using TextMate. Still good.

While we hear more about new tech, it’s old tech that is more well known, including what it’s bad at. If newer tech, perhaps more complicated tech, is needed because it solves a known pain point, that’s great, but when it doesn’t…

You are perfectly okay to stick with what works for you. The more you use something, the clearer its pain points become. Try new technologies when you’re ready to address those pain points. Don’t feel obligated to change your workflow because of chatter. New tech gets chatter, but that doesn’t make it any better.

Adam Silver says that a boring developer is full of questions:

“Will debugging code be more difficult?”, “Might performance degrade?” and “Will I be slowed down due to compile times?”

Dan Kim is also proud of being boring:

I have a confession to make — I’m not a rock star programmer. Nor am I a hacker. I don’t know ninjutsu. Nobody has ever called me a wizard.

Still, I take pride in the fact that I’m a good, solid programmer.

Complexity isn’t an enemy. Complexity is valuable. If what we work on had no complexity, it would worth far less, as there would be nothing slowing down the competition. Our job is complexity. Or rather, our job is managing the level of complexity so it’s valuable while still manageable.

Santi Metz has a great article digging into various aspects of this, part of which is about considering how much complicated code needs to change:

We abhor complication, but if the code never changes, it’s not costing us money.

Your CMS might be extremely complicated under the hood, but if you never touch that, who cares. But if your CMS limits what you’re able to do, and you spend a lot of time fighting it, that complexity matters a lot.

It’s satisfying to read Sandi’s analysis that it’s possible to predict where code breaks, and those points are defined by complexity. “Outlier classes” (parts of a code base that cause the most problems) can be identified without even seeing the code base:

I’m not familiar with the source code for these apps, but sight unseen I feel confident making a few predictions about the outlying classes. I suspect that they:

  1. are larger than most other classes,
  2. are laden with conditionals, and
  3. represent core concepts in the domain

I feel seen.

Boring is in it for the long haul.

Cap Watkins writes in “The Boring Designer”:

The boring designer is trusted and valued because people know they’re in it for the product and the user. The boring designer asks questions and leans on others’ experience and expertise, creating even more trust over time. They rarely assume they know the answer.

The boring designer is capable of being one of the best leaders a team can have.

So be great. Be boring.

Be boring!

The post Simple & Boring appeared first on CSS-Tricks.

All About mailto: Links

You can make a garden variety anchor link (<a>) open up a new email. Let’s take a little journey into this feature. It’s pretty easy to use, but as with anything web, there are lots of things to consider.

The basic functionality

<a href="mailto:someone@yoursite.com">Email Us</a>

It works!

But we immediately run into a handful of UX issues. One of them is that clicking that link surprises some people in a way they don’t like. Sort of the same way clicking on a link to a PDF opens a file instead of a web page. Le sigh. We’ll get to that in a bit.

“Open in new tab” sometimes does matter.

If a user has their default mail client (e.g. Outlook, Apple Mail, etc.) set up to be a native app, it doesn’t really matter. They click a mailto: link, that application opens up, a new email is created, and it behaves the same whether you’ve attempted to open that link in a new tab or not.

But if a user has a browser-based email client set up, it does matter. For example, you can allow Gmail to be your default email handler on Chrome. In that case, the link behaves like any other link, in that if you don’t open in a new tab, the page will redirect to Gmail.

I’m a little on the fence about it. I’ve weighed in on opening links in new tabs before, but not specifically about opening emails. I’d say I lean a bit toward using target="_blank" on mail links, despite my feelings on using it in other scenarios.

<a href="mailto:someone@yoursite.com" target="_blank" rel="noopener noreferrer">Email Us</a>

Adding a subject and body

This is somewhat rare to see for some reason, but mailto: links can define the email subject and body content as well. They are just query parameters!

mailto:chriscoyier@gmail.com?subject=Important!&body=Hi.

Add copy and blind copy support

You can send to multiple email addresses, and even carbon copy (CC), and blind carbon copy (BCC) people on the email. The trick is more query parameters and comma-separating the email addresses.

mailto:someone@yoursite.com?cc=someoneelse@theirsite.com,another@thatsite.com,me@mysite.com&bcc=lastperson@theirsite.com

This site is awful handy

mailtolink.me will help generate email links.

Use a <form> to let people craft the email first

I’m not sure how useful this is, but it’s an interesting curiosity that you can make a <form> do a GET, which is basically a redirect to a URL — and that URL can be in the mailto: format with query params populated by the inputs! It can even open in a new tab.

See the Pen
Use a <form> to make an email
by Chris Coyier (@chriscoyier)
on CodePen.

People don’t like surprises

Because mailto: links are valid anchor links like any other, they are typically styled exactly the same. But clicking them clearly produces very different results. It may be worthwhile to indicate mailto: links in a special way.

If you use an actual email address as the link, that’s probably a good indication:

<a href="mailto:chriscoyier@gmail.com">chriscoyier@gmail.com</a>

Or you could use CSS to help explain with a little emoji story:

a[href^="mailto:"]::after { content: " (&#x1f4e8;&#x2197;&#xfe0f;)";
}

If you really dislike mailto: links, there is a browser extension for you.

https://ihatemailto.com/

I dig how it doesn’t just block them, but copies the email address to your clipboard and tells you that’s what it did.

The post All About mailto: Links appeared first on CSS-Tricks.

Advanced Tooling for Web Components

Over the course of the last four articles in this five-part series, we’ve taken a broad look at the technologies that make up the Web Components standards. First, we looked at how to create HTML templates that could be consumed at a later time. Second, we dove into creating our own custom element. After that, we encapsulated our element’s styles and selectors into the shadow DOM, so that our element is entirely self-contained.

We’ve explored how powerful these tools can be by creating our own custom modal dialog, an element that can be used in most modern application contexts regardless of the underlying framework or library. In this article, we will look at how to consume our element in the various frameworks and look at some advanced tooling to really ramp up your Web Component skills.

Article Series:

  1. An Introduction to Web Components
  2. Crafting Reusable HTML Templates
  3. Creating a Custom Element from Scratch
  4. Encapsulating Style and Structure with Shadow DOM
  5. Advanced Tooling for Web Components (This post)

Framework agnostic

Our dialog component works great in almost any framework or even without one. (Granted, if JavaScript is disabled, the whole thing is for naught.) Angular and Vue treat Web Components as first-class citizens: the frameworks have been designed with web standards in mind. React is slightly more opinionated, but not impossible to integrate.

Angular

First, let’s take a look at how Angular handles custom elements. By default, Angular will throw a template error whenever it encounters an element it doesn’t recognize (i.e. the default browser elements or any of the components defined by Angular). This behavior can be changed by including the CUSTOM_ELEMENTS_SCHEMA.

…allows an NgModule to contain the following:

  • Non-Angular elements named with dash case (-).
  • Element properties named with dash case (-). Dash case is the naming convention for custom elements.

Angular Documentation

Consuming this schema is as simple as adding it to a module:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @NgModule({ /** Omitted */ schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class MyModuleAllowsCustomElements {}

That’s it. After this, Angular will allow us to use our custom element wherever we want with the standard property and event bindings:

<one-dialog [open]="isDialogOpen" (dialog-closed)="dialogClosed($event)"> <span slot="heading">Heading text</span> <div> <p>Body copy</p> </div>
</one-dialog>

Vue

Vue’s compatibility with Web Components is even better than Angular’s as it doesn’t require any special configuration. Once an element is registered, it can be used with Vue’s default templating syntax:

<one-dialog v-bind:open="isDialogOpen" v-on:dialog-closed="dialogClosed"> <span slot="heading">Heading text</span> <div> <p>Body copy</p> </div>
</one-dialog>

One caveat with Angular and Vue, however, is their default form controls. If we wish to use something like reactive forms or [(ng-model)] in Angular or v-model in Vue on a custom element with a form control, we will need to set up that plumbing for which is beyond the scope of this article.

React

React is slightly more complicated than Angular. React’s virtual DOM effectively takes a JSX tree and renders it as a large object. So, instead of directly modifying attributes on HTML elements like Angular or Vue, React uses an object syntax to track changes that need to be made to the DOM and updates them in bulk. This works just fine in most cases. Our dialog’s open attribute is bound to its property and will respond perfectly well to changing props.

The catch comes when we start to look at the CustomEvent dispatched when our dialog closes. React implements a series of native event listeners for us with their synthetic event system. Unfortunately, that means that controls like onDialogClosed won’t actually attach event listeners to our component, so we have to find some other way.

The most obvious means of adding custom event listeners in React is by using DOM refs. In this model, we can reference our HTML node directly. The syntax is a bit verbose, but works great:

import React, { Component, createRef } from 'react'; export default class MyComponent extends Component { constructor(props) { super(props); // Create the ref this.dialog = createRef(); // Bind our method to the instance this.onDialogClosed = this.onDialogClosed.bind(this); this.state = { open: false }; } componentDidMount() { // Once the component mounds, add the event listener this.dialog.current.addEventListener('dialog-closed', this.onDialogClosed); } componentWillUnmount() { // When the component unmounts, remove the listener this.dialog.current.removeEventListener('dialog-closed', this.onDialogClosed); } onDialogClosed(event) { /** Omitted **/ } render() { return <div> <one-dialog open={this.state.open} ref={this.dialog}> <span slot="heading">Heading text</span> <div> <p>Body copy</p> </div> </one-dialog> </div> }
}

Or, we can use stateless functional components and hooks:

import React, { useState, useEffect, useRef } from 'react'; export default function MyComponent(props) { const [ dialogOpen, setDialogOpen ] = useState(false); const oneDialog = useRef(null); const onDialogClosed = event => console.log(event); useEffect(() => { oneDialog.current.addEventListener('dialog-closed', onDialogClosed); return () => oneDialog.current.removeEventListener('dialog-closed', onDialogClosed) }); return <div> <button onClick={() => setDialogOpen(true)}>Open dialog</button> <one-dialog ref={oneDialog} open={dialogOpen}> <span slot="heading">Heading text</span> <div> <p>Body copy</p> </div> </one-dialog> </div>
}

That’s not bad, but you can see how reusing this component could quickly become cumbersome. Luckily, we can export a default React component that wraps our custom element using the same tools.

import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types'; export default class OneDialog extends Component { constructor(props) { super(props); // Create the ref this.dialog = createRef(); // Bind our method to the instance this.onDialogClosed = this.onDialogClosed.bind(this); } componentDidMount() { // Once the component mounds, add the event listener this.dialog.current.addEventListener('dialog-closed', this.onDialogClosed); } componentWillUnmount() { // When the component unmounts, remove the listener this.dialog.current.removeEventListener('dialog-closed', this.onDialogClosed); } onDialogClosed(event) { // Check to make sure the prop is present before calling it if (this.props.onDialogClosed) { this.props.onDialogClosed(event); } } render() { const { children, onDialogClosed, ...props } = this.props; return <one-dialog {...props} ref={this.dialog}> {children} </one-dialog> }
} OneDialog.propTypes = { children: children: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.node), PropTypes.node ]).isRequired, onDialogClosed: PropTypes.func
};

…or again as a stateless, functional component:

import React, { useRef, useEffect } from 'react';
import PropTypes from 'prop-types'; export default function OneDialog(props) { const { children, onDialogClosed, ...restProps } = props; const oneDialog = useRef(null); useEffect(() => { onDialogClosed ? oneDialog.current.addEventListener('dialog-closed', onDialogClosed) : null; return () => { onDialogClosed ? oneDialog.current.removeEventListener('dialog-closed', onDialogClosed) : null; }; }); return <one-dialog ref={oneDialog} {...restProps}>{children}</one-dialog>
}

Now we can use our dialog natively in React, but still keep the same API across all our applications (and still drop classes, if that’s your thing).

import React, { useState } from 'react';
import OneDialog from './OneDialog'; export default function MyComponent(props) { const [open, setOpen] = useState(false); return <div> <button onClick={() => setOpen(true)}>Open dialog</button> <OneDialog open={open} onDialogClosed={() => setOpen(false)}> <span slot="heading">Heading text</span> <div> <p>Body copy</p> </div> </OneDialog> </div>
}

Advanced tooling

There are a number of great tools for authoring your own custom elements. Searching through npm reveals a multitude of tools for creating highly-reactive custom elements (including my own pet project), but the most popular today by far is lit-html from the Polymer team and, more specifically for Web Components, LitElement.

LitElement is a custom elements base class that provides a series of APIs for doing all of the things we’ve walked through so far. It can be run in a browser without a build step, but if you enjoy using future-facing tools like decorators, there are utilities for that as well.

Before diving into how to use lit or LitElement, take a minute to familiarize yourself with tagged template literals, which are a special kind of function called on template literal strings in JavaScript. These functions take in an array of strings and a collection of interpolated values and can return anything you might want.

function tag(strings, ...values) { console.log({ strings, values }); return true;
}
const who = 'world'; tag`hello ${who}`; /** would log out { strings: ['hello ', ''], values: ['world'] } and return true **/

What LitElement gives us is live, dynamic updating of anything passed to that values array, so as a property updates, the element’s render function would be called and the resulting DOM would be re-rendered

import { LitElement, html } from 'lit-element'; class SomeComponent { static get properties() { return { now: { type: String } }; } connectedCallback() { // Be sure to call the super super.connectedCallback(); this.interval = window.setInterval(() => { this.now = Date.now(); }); } disconnectedCallback() { super.disconnectedCallback(); window.clearInterval(this.interval); } render() { return html`<h1>It is ${this.now}</h1>`; }
} customElements.define('some-component', SomeComponent);

See the Pen
LitElement now example
by Caleb Williams (@calebdwilliams)
on CodePen.

What you will notice is that we have to define any property we want LitElement to watch using the static properties getter. Using that API tells the base class to call render whenever a change is made to the component’s properties. render, in turn, will update only the nodes that need to change.

So, for our dialog example, it would look like this using LitElement:

See the Pen
Dialog example using LitElement
by Caleb Williams (@calebdwilliams)
on CodePen.

There are several variants of lit-html available, including Haunted, a React hooks-style library for Web Components that can also make use of virtual components using lit-html as a base.

At the end of the day, most of the modern Web Components tools are various flavors of what LitElement is: a base class that abstracts common logic away from our components. Among the other flavors are Stencil, SkateJS, Angular Elements and Polymer.

What’s next

Web Components standards are continuing to evolve and new features are being discussed and added to browsers on an ongoing basis. Soon, Web Component authors will have APIs for interacting with web forms at a high level (including other element internals that are beyond the scope of these introductory articles), like native HTML and CSS module imports, native template instantiation and updating controls, and many more which can be tracked on the W3C/web components issues board on GitHub.

These standards are ready to adopt into our projects today with the appropriate polyfills for legacy browsers and Edge. And while they may not replace your framework of choice, they can be used alongside them to augment you and your organization’s workflows.

The post Advanced Tooling for Web Components appeared first on CSS-Tricks.

Using for Menus and Dialogs is an Interesting Idea

One of the most empowering things you can learn as a new front-end developer who is starting to learn JavaScript is to change classes. If you can change classes, you can use your CSS skills to control a lot on a page. Toggle a class to one thing, style it this way, toggle to another class (or remove it) and style it another way.

But there is an HTML element that also does toggles! <details>! For example, it’s definitely the quickest way to build an accordion UI.

Extending that toggle-based thinking, what is a user menu if not for a single accordion? Same with modals. If we went that route, we could make JavaScript optional on those dynamic things. That’s exactly what GitHub did with their menu.

Inside the <details> element, GitHub uses some Web Components (that do require JavaScript) to do some bonus stuff, but they aren’t required for basic menu functionality. That means the menu is resilient and instantly interactive when the page is rendered.

Mu-An Chiou, a web systems engineer at GitHub who spearheaded this, has a presentation all about this!

The worst strike on <details> is its browser support in Edge, but I guess we won’t have to worry about that soon, as Edge will be using Chromium… soon? Does anyone know?

The post Using <details> for Menus and Dialogs is an Interesting Idea appeared first on CSS-Tricks.

Technical Debt is Like Tetris

Here’s a wonderful post by Eric Higgins all about refactoring and technical debt. He compares giant refactoring projects to being similar to Tetris:

Similar to running a business, Tetris gets harder the longer you play. Pieces move faster and it becomes harder to keep up.

Similar to running a business, you can never win Tetris. There is no true finish line. You only control how quickly you lose.

Similar to running a business, allowing too many gaps to build up in Tetris will cause you to lose.

I love this comparison, despite my mediocre Tetris skills. It does feel like even “easy” development becomes harder as technical debt grows on a project, much the same way Tetris pieces gain speed and provide little time to react as the stack grows. However, I do think perhaps I have a more optimistic view of technical debt overall. If you work slowly and carefully then you can build up a culture of refactoring and gather momentum over time.

Direct Link to ArticlePermalink

The post Technical Debt is Like Tetris appeared first on CSS-Tricks.

It’s pretty cool how Netlify CMS works with any flat file site generator

Little confession here: when I first saw Netlify CMS at a glance, I thought: cool, maybe I’ll try that someday when I’m exploring CMSs for a new project. Then as I looked at it with fresh eyes: I can already use this! It’s a true CMS in that it adds a content management UI on top of any static site generator that works from flat files! Think of how you might build a site from markdown files with Gatsby, Jekyll, Hugo, Middleman, etc. You can create and edit Markdown files and the site’s build process runs and the site is created.

Netlify CMS gives you (or anyone you set it up for) a way to create/edit those Markdown files without having to use a code editor or know about Pull Requests on GitHub or anything. It’s a little in-browser app that gives you a UI and does the file manipulation and Git stuff behind the scenes.

Here’s an example.

Our conferences website is a perfect site to build with a static site generator.

It’s on GitHub, so it’s open to Pull Requests, and each conference is a Markdown file.

That’s pretty cool already. The community has contributed 77 Pull Requests already really fleshing out the content of the site, and the design, accessibility, and features as well!

I used 11ty to build the site, which works great with building out those Markdown files into a site, using Nunjucks templates. Very satisfying combo, I found, after a slight mostly configuration-related learning curve.

Enter Netlify CMS.

But as comfortable as you or I might be with a quick code edit and Pull Request, not everybody is. And even I have to agree that going to a URL quick, editing some copy in input fields, and clicking a save button is the easiest possible way to manage content.

That CMS UI is exactly what Netlify CMS gives you. Wanna see the entire commit for adding Netlify CMS?

It’s two files! That still kinda blows my mind. It’s a little SPA React app that’s entirely configurable with one file.

Cutting to the chase here, once it is installed, I now have a totally customized UI for editing the conferences on the site available right on the production site.

Netlify CMS doesn’t do anything forceful or weird, like attempt to edit the HTML on the production site directly. It works right into the workflow in the same exact way that you would if you were editing files in a code editor and committing in Git.

Auth & Git

You use Netlify CMS on your production site, which means you need authentication so that just you (and the people you want) have access to it. Netlify Identity makes that a snap. You just flip it on from your Netlify settings and it works.

I activated GitHub Auth so I could make logging in one-click for me.

The Git magic happens through a technology called Git Gateway. You don’t have to understand it (I don’t really), you just enable it in Netlify as part of Netlify Identity, and it forms the connection between your site and the Git repository.

Now when you create/edit content, actual Markdown files are created and edited (and whatever else is involved, like images!) and the change happens right in the Git repository.


I made this the footer of the site cause heck yeah.

The post It’s pretty cool how Netlify CMS works with any flat file site generator appeared first on CSS-Tricks.