Thursday, 30 April 2020

The Hero Generator

Sarah:

I’ve had to implement the same hero for several years now, so like a good lazy programmer, I figured I’d automate it.

Direct Link to ArticlePermalink

The post The Hero Generator appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2x9U7Lc
via IFTTT

CSS-Tricks Chronicle XXXVIII

Hey hey, these “chronicle” posts are little roundups of news that I haven’t gotten a chance to link up yet. They are often things that I’ve done off-site, like be a guest on a podcast or online conference. Or it’s news from other projects I work on. Or some other thing I’ve been meaning to shout out. Stuff like that! Enjoy the links!

I chatted with Paul Campbell the other day during Admission Online, an online conference put together by the Tito crew . They’ve published all the videos there including mine.

I had a chance to chat with Paul about his Tito service about last year on ShopTalk in a really great episode. Tito is a best-in-class software tool for running a conference. It helps you build a site, sell tickets, manage attendees, run reports, and all that. Clearly the COVID-19 situation has impacted that business a lot, so I admire the accelerated pivot they are doing by creating Vito, a new platform for running online conferences, and running these conferences super quickly as a way to showcase it. If you’re running an online conference, I’d get on that invite list ASAP.

Jina Anne has been doing something new as well in the online event space. She’s been doing these 30-minute AMA (Ask Me Anything) sessions with interesting folks (excluding me). Upcoming events are here. They are five bucks, and that gets you live access and the ability to actually ask a question. Jina publishes past events to YouTube. Here’s one with me:

I was interviewed on Balance the Grid. Here’s one exchange:

What do you think are some of the best habits or routines that you’ve developed over the years to help you achieve success in your life?

I’m quite sure I have more bad habits than good, so take all this with a bucket of salt. But one thing I like to do is to try to make as much of the time I spend working is spent working on something of lasting value.

That’s why I like to blog, for example. If I finish a blog post, that’s going to be published at a URL and that URL is going to get some traffic now, and at least a little bit of traffic forever. The more I do that the more I build out my base of lasting content that will serve me forever.

Over at CodePen, we’ve been busier than ever working toward our grand vision of what CodePen can become. We have a ton of focus on things lately, despite this terrible pandemic. It’s nice to be able to stay heads down into work you find important and meaningful in the best of times, and if that can be a mental escape as well, well, I’ll take it.

We’ve been building more community-showcasing features. On our Following page there are no less than three new features: (1) A “Recent” feed¹, (2) a “Top” feed, and (3) Follow suggestions. The Following page should be about 20× more interesting by my calculation! For example, the recent feed is the activity of all the people you follow, surfacing things you likely won’t want to miss.

You can toggle that feed from “Recent” over to “Top.” While that seems like a minor change, it’s actually an entirely different feed that we create that is like a ranked popularity feed, only scoped to people you follow.

Below that is a list of other recommended CodePen folks to follow that’s created just for you. I can testify that CodePen is a lot more fun when you follow people that create things you like, and that’s a fact we’re going to keep making more and more true.

We’re always pushing out little stuff, but while I’m focusing on big new things, the biggest is the fact that we’ve taken some steps toward “Custom Editors.” That is, Pen Editors that can do things that our normal Pen Editor can’t do. We’ve released two: Flutter and Vue Single File Components.

  1. The word “feed” is new. We don’t actually use that term on the site. It’s a word we use internally on the team and what’s used by the technology we’re using. But I think it’s a good general description for the CodePen community as well, since CodePen is a developer-facing site anyway. I suppose “stream” is also a good descriptor (and just so happens to be the literal name of the tech we’re using.

This is about the time of year I would normally be telling you about the Smashing Conference I went to and the wonderful time I had there, but those in-person conferences have, of course, been re-scheduled for later in the year. At the moment, I’m still planning on Austin in October and San Francisco in November, but of course, nobody knows what the world will be like then. One thing is for sure though: online workshops. Smashing has been doing lots of these, and many of them are super deep courses that take place over several weeks.

Lots of conferences are going online and that’s kinda cool to see. It widens the possibility that anyone in the world can join, which is the web at its best. Conferences like All Day Hey are coming up in a few weeks (and is only a handful of bucks). Jamstack Conf is going virtual in May. My closest-to-home conference this year, CascadiaJS, is going virtual in September.

I got to be on the podcast Coding Zeal. I can’t figure out how to embed a BuzzSprout episode, so here’s a link.

The post CSS-Tricks Chronicle XXXVIII appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/3aSke7t
via IFTTT

Some Innocent Fun With HTML Video and Progress

The idea came while watching a mandatory training video on bullying in the workplace. I can just hear High School Geoff LOL-ing about a wimp like me have to watch that thing.

But here we are.

The video UI was actually lovely, but it was the progress bar that really caught my attention – or rather the [progress].value. It was a simple gradient going from green to blue that grew as the video continued playing.

If only I had this advice in high school…

I already know it’s possible to create the same sort gradient on the <progress> element. Pankaj Parashar demonstrated that in a CSS-Tricks post back in 2016.

I really wanted to mock up something similar but haven’t played around with video all that much. I’m also no expert in JavaScript. But how hard can that actually be? I mean, all I want to do is get know how far we are in the video and use that to update the progress value. Right?

My inner bully made so much fun of me that I decided to give it a shot. It’s not the most complicated thing in the world, but I had some fun with it and wanted to share how I set it up in this demo.

The markup

HTML5 all the way, baby!

<figure>
  <video id="video" src="http://html5videoformatconverter.com/data/images/happyfit2.mp4"></video>
  <figcaption>
    <button id="play" aria-label="Play" role="button">►</button>
    <progress id="progress" max="100" value="0">Progress</progress>
    </figcaotion>
</figure>

The key line is this:

<progress id="progress" max="100" value="0">Progress</progress>

The max attribute tells us we’re working with 100 as the highest value while the value attribute is starting us out at zero. That makes sense since it allows us to think of the video’s progress in terms of a percentage, where 0% is the start and 100% is the end, and where our initial starting point is 0%.

Styling

I’m definitely not going to get deep into the process of styling the <progress> element in CSS. The Pankaj post I linked up earlier already does a phenomenal job of that. The CSS we need to paint a gradient on the progress value looks like this:

/* Fallback stuff */
progress[value] {
  appearance: none; /* Needed for Safari */
  border: none; /* Needed for Firefox */
  color: #e52e71; /* Fallback to a solid color */
}

/* WebKit styles */
progress[value]::-webkit-progress-value {
  background-image: linear-gradient(
    to right,
    #ff8a00, #e52e71
  );
  transition: width 1s linear;
}

/* Firefox styles */
progress[value]::-moz-progress-bar {
  background-image: -moz-linear-gradient(
    to right,
    #ff8a00, #e52e71
  );
}

The trick is to pay attention to the various nuances that make it cross-browser compatible. Both WebKit and Mozilla browsers have their own particular ways of handling progress elements. That makes the styling a little verbose but, hey, what can you do?

Getting the progress value from a video

I knew there would be some math involved if I wanted to get the current time of the video and display it as a value expressed as a percentage. And if you thought that being a nerd in high school gained me mathematical superpowers, well, sorry to disappoint.

I had to write down an outline of what I thought needed to happen:

  • Get the current time of the video. We have to know where the video is at if we want to display it as the progress value.
  • Get the video duration. Knowing the video’s length will help express the current time as a percent.
  • Calculate the progress value. Again, we’re working in percents. My dusty algebra textbook tells me the formula is part / whole = % / 100. In the context of the video, we can re-write that as currentTime / duration = progress value.

That gives us all the marching orders we need to get started. In fact, we can start creating variables for the elements we need to select and figure out which properties we need to work with to fill in the equation.

// Variables
const progress = document.getElementById( "progress" );

// Properties
// progress.value = The calculated progress value as a percent of 100
// video.currentTime = The current time of the video in seconds
// video.duration = The length of the video in seconds

Not bad, not bad. Now we need to calculate the progress value by plugging those things into our equation.

function progressLoop() {
  setInterval(function () {
    document.getElementById("progress").value = Math.round(
      (video.currentTime / video.duration) * 100
    );
  });
}

I’ll admit: I forgot that the equation would result to decimal values. That’s where Math.round() comes into play to update those to the nearest whole integer.

That actually gets the gradient progress bar to animate as the video plays!

I thought I could call this a win and walk away happy. Buuuut, there were a couple of things bugging me. Plus, I was getting errors in the console. No bueno.

Showing the current time

Not a big deal, but certainly a nice-to-have. We can chuck a timer next to the progress bar and count seconds as we go. We already have the data to do it, so all we need is the markup and to hook it up.

Let’s add a wrap the time in a <label> since the <progress> element can have one.

<figure>
  <video controls id="video" src="http://html5videoformatconverter.com/data/images/happyfit2.mp4"></video>
  <figcaption>
    <label id="timer" for="progress" role="timer"></label>
    <progress id="progress" max="100" value="0">Progress</progress>
    </figcaotion>
</figure>

Now we can hook it up. We’ll assign it a variable and use innerHTML to print the current value inside the label.

const progress = document.getElementById("progress");
const timer = document.getElementById( "timer" );

function progressLoop() {
  setInterval(function () {
    progress.value = Math.round((video.currentTime / video.duration) * 100);
    timer.innerHTML = Math.round(video.currentTime) + " seconds";
  });
}

progressLoop();

Hey, that works!

Extra credit would involve converting the timer to display in HH:MM:SS format.

Adding a play button

The fact there there were two UIs going on at the same time sure bugged me. the <video> element has a controls attribute that, when used, shows the video controls, like play, progress, skip, volume, and such. Let’s leave that out.

But that means we need — at the very minimum — to provide a way to start and stop the video. Let’s button that up.

First, add it to the HTML:

<figure>
  <video id="video" src="http://html5videoformatconverter.com/data/images/happyfit2.mp4"></video>
  <figcaption>
    <label id="timer" for="progress" role="timer"></label>
    <button id="play" aria-label="Play" role="button">►</button>
    <progress id="progress" max="100" value="0">Progress</progress>
    </figcaotion>
</figure>

Then, hook it up with a function that toggles the video between play and pause on click.

button = document.getElementById( "play" );

function playPause() { 
  if ( video.paused ) {
    video.play();
    button.innerHTML = "❙❙";
  }
  else  {
    video.pause(); 
    button.innerHTML = "►";
  }
}

button.addEventListener( "click", playPause );
video.addEventListener("play", progressLoop);

Hey, it’s still working!

I know it seems weird to take out the rich set of controls that HTML5 offers right out of the box. I probably wouldn’t do that on a real project, but we’re just playing around here.

Cleaning up my ugly spaghetti code

I really want to thank my buddy Neal Fennimore. He took time to look at this with me and offer advice that not only makes the code more legible, but does a much, much better job defining states…

// States
const PAUSED = 'paused';
const PLAYING = 'playing';

// Initial state
let state = PAUSED;

…doing a proper check for the state before triggering the progress function while listening for the play, pause and click events…

// Animation loop
function progressLoop() {
  if(state === PLAYING) {
    progress.value = Math.round( ( video.currentTime / video.duration ) * 100 );
    timer.innerHTML = Math.round( video.currentTime ) + ' seconds';
    requestAnimationFrame(progressLoop);
  }
}

video.addEventListener('play', onPlay);
video.addEventListener('pause', onPause);
button.addEventListener('click', onClick);

…and even making the animation more performant by replacing setInterval with requestAnimationFrame as you can see highlighted in that same snippet.

Here it is in all its glory!

Oh, and yes: I was working on this while “watching” the training video. And, I aced the quiz at the end, thank you very much. 🤓

The post Some Innocent Fun With HTML Video and Progress appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/35l0gRx
via IFTTT

Real-World Effectiveness of Brotli

Harry Roberts:

The numbers so far show that the difference between no compression and Gzip are vast, whereas the difference between Gzip and Brotli are far more modest. This suggests that while the nothing to Gzip gains will be noticeable, the upgrade from Gzip to Brotli might perhaps be less impressive.

The rub?

Gzip made files 72% smaller than not compressing them at all, but Brotli only saved us an additional 5.7% over that. In terms of FCP, Gzip gave us a 23% improvement when compared to using nothing at all, but Brotli only gained us an extra 3.5% on top of that.

So Brotli is just like spicy gzip.

Still, I’ll take a handful of points by flipping a switch in Cloudflare.

Direct Link to ArticlePermalink

The post Real-World Effectiveness of Brotli appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/3eJZIZy
via IFTTT

A Book Apart Turning 10

Early congratulations, A Book Apart! That’s a hell of a milestone. I’m quite sure I’ve read more A Book Apart books than any other tech book publisher.

Katel LeDu runs the ship over there, and she’s given me very special pack of discount codes that will get you my book, Practical SVG, for free. So now it’s my job to get you those codes. There are only 10 of them—not enough for everyone. So I’m going to do some low-down, dirty-rotten, absolutely-shameless cross-marketing: I’m going to give them to the first 10 people who are CodePen PRO who email me at chriscoyier@gmail.com. CodePen PRO is only $12/month if you pay monthly or $8/month if you pay yearly, and this discount code is worth $14, so in the end, you get both and save a few bucks. If you’re already PRO, cool, thanks, you still qualify.

You know what’s cool about Practical SVG? Even though I wrote it 4 years ago, SVG just doesn’t change that fast, so I’d say 90%+ I wouldn’t even change in a re-write. If you’re just learning about SVG as a front-end developer, it’s a fine choice.

In addition to my conniving scheme above, if you just really would like this book and have zero budget for it, or know someone else in that situation, you can also email me about that and we’ll work it out. I just may have a few copies around here I could get you. Hey, I’m trying to make money off you but I ain’t trying to lock away knowledge from anyone that really needs it.

The post A Book Apart Turning 10 appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2SoitIu
via IFTTT

Wednesday, 29 April 2020

Click Once, Select All; Click Again, Select Normally

A bonafide CSS trick from Will Boyd!

  1. Force all the content of an element to be selected when clicked with user-select: all;
  2. If you click a second time, let the user select just parts of the text as normal.
  3. Second click? Well, it’s a trick. You’re really using a time-delayed forwards-ending @keyframes animation when the element is in :focus to change it to user-select: text;

Will’s article has a bunch of more useful information and use-cases for user-select.

Direct Link to ArticlePermalink

The post Click Once, Select All; Click Again, Select Normally appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2yPPyGg
via IFTTT

[David Baron’s] Thoughts on an implementable path forward for Container Queries

That’s the title of a public post from David Baron, a Principal Engineer at Firefox, with thoughts toward container queries. I know a lot of people have been holding their breath waiting for David’s ideas, as he’s one of few uniquely qualified to understand the ins and outs of this and speak to implementation possibility.

We’re still in the early stages of container queries. Every web designer and developer wants them, the browsers know it, but it’s a super complicated situation. It was very encouraging in February 2020 to hear positive signals about a possible switch-statement syntax that would give us access to an available-inline-size used to conditionally set individual values.

Now we’re seeing a second idea that is also in the realm of the possible.

This ideas uses an @rule instead for the syntax. From the document:

@container <selector> (<container-media-query>)? {
  // ... rules ...
}

So I’m imagining it like:

.parent {
  contain: layout inline-size;
  display: grid;
  grid-template-columns: 100%;
  gap: 1rem;
}
@container .parent (min-width: 400px) {
  grid-template-columns: 1fr 1fr;

  .child::before {
     content: "Hello from container query land!";
   }
}

Except…

  1. I’m not sure if you’d have to repeat the selector inside as well? Or if dropping property/value pairs in there automatically applies to the selector in the @rule.
  2. David says “The rules can match only that container’s descendants. Probably we’d need support for some properties applying to the container itself, but others definitely can’t.” I’d hope grid properties are a strong contender for something you can change, but I have no idea. Otherwise, I think we’d see people wrapping elements with <div class="container-query"> to get around the “only descendants” limit.

Containment seems to be a very important part of this. Like if the element isn’t property contained, the container query just won’t work. I don’t know that much about containment, but Rachel has a great deep dive from late last year.

Again, this is super early days, I’m just having fun watching this and none of us really have any idea what will actually make it to browsers.

Direct Link to ArticlePermalink

The post [David Baron’s] Thoughts on an implementable path forward for Container Queries appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/38cnQzS
via IFTTT

Alpine.js: The JavaScript Framework That’s Used Like jQuery, Written Like Vue, and Inspired by TailwindCSS

We have big JavaScript frameworks that tons of people already use and like, including React, Vue, Angular, and Svelte. Do we need another JavaScript library? Let’s take a look at Alpine.js and you can decide for yourself. Alpine.js is for developers who aren’t looking to build a single page application (SPA). It’s lightweight (~7kB gzipped) and designed to write markup-driven client-side JavaScript.

The syntax is borrowed from Vue and Angular directive. That means it will feel familiar if you’ve worked with those before. But, again, Alpine.js is not designed to build SPAs, but rather enhance your templates with a little bit of JavaScript.

For example, here’s an Alpine.js demo of an interactive “alert” component.

The alert message is two-way bound to the input using x-model="msg". The “level” of the alert message is set using a reactive level property. The alert displays when when both msg and level have a value.

It’s like a replacement for jQuery and JavaScript, but with declarative rendering

Alpine.js is a Vue template-flavored replacement for jQuery and vanilla JavaScript rather than a React/Vue/Svelte/WhateverFramework competitor.

Since Alpine.js is less than a year old, it can make assumptions about DOM APIs that jQuery cannot. Let’s briefly draw a comparison between the two.

Querying vs. binding

The bulk of jQuery’s size and features comes in the shape of a cross-browser compatibility layer over imperative DOM APIs — this is usually referred to as jQuery Core and sports features that can query the DOM and manipulate it.

The Alpine.js answer to jQuery core is a declarative way to bind data to the DOM using the x-bind attribute binding directive. It can be used to bind any attribute to reactive data on the Alpine.js component. Alpine.js, like its declarative view library contemporaries (React, Vue), provides x-ref as an escape hatch to directly access DOM elements from JavaScript component code when binding is not sufficient (eg. when integrating a third-party library that needs to be passed a DOM Node).

Handling events

jQuery also provides a way to handle, create and trigger events. Alpine.js provides the x-on directive and the $event magic value which allows JavaScript functions to handle events. To trigger (custom) events, Alpine.js provides the $dispatch magic property which is a thin wrapper over the browser’s Event and Dispatch Event APIs.

Effects

One of jQuery’s key features is its effects, or rather, it’s ability to write easy animations. Where we might use slideUp, slideDown, fadeIn, fadeOut properties in jQuery to create effects, Alpine.js provides a set of x-transition directives, which add and remove classes throughout the element’s transition. That’s largely inspired by the Vue Transition API.

Also, jQuery’s Ajax client has no prescriptive solution in Alpine.js, thanks to the Fetch API or taking advantage of a third party HTTP library (e.g. axios, ky, superagent).

Plugins

It’s also worth calling out jQuery plugins. There is no comparison to that (yet) in the Alpine.js ecosystem. Sharing Alpine.js components is relatively simple, usually requiring a simple case of copy and paste. The JavaScript in Alpine.js components are “just functions” and tend not to access Alpine.js itself, making them relatively straightforward to share by including them on different pages with a script tag. Any magic properties are added when Alpine initializes or is passed into bindings, like $event in x-on bindings.

There are currently no examples of Alpine.js extensions, although there are a few issues and pull requests to add “core” events that hook into Alpine.js from other libraries. There are also discussions happening about the ability to add custom directives. The stance from Alpine.js creator Caleb Porzio, seems to be basing API decisions on the Vue APIs, so I would expect that any future extension point would be inspired on what Vue.js provides.

Size

Alpine.js is lighter weight than jQuery, coming in at 21.9kB minified — 7.1kB gzipped — compared to jQuery at 87.6kB minified — 30.4kB minified and gzipped. Only 23% the size!

Most of that is likely due to the way Alpine.js focuses on providing a declarative API for the DOM (e.g. attribute binding, event listeners and transitions).

Bundlephobia breaks down the two

For the sake of comparison, Vue comes in at 63.5kB minified (22.8kB gzipped). How can Alpine.js come in lighter despite it’s API being equivalent Vue? Alpine.js does not implement a Virtual DOM. Instead, it directly mutates the DOM while exposing the same declarative API as Vue.

Let’s look at an example

Alpine is compact because since application code is declarative in nature, and is declared via templates. For example, here’s a Pokemon search page using Alpine.js:

This example shows how a component is set up using x-data and a function that returns the initial component data, methods, and x-init to run that function on load.

Bindings and event listeners in Alpine.js with a syntax that’s strikingly similar to Vue templates.

  • Alpine: x-bind:attribute="express" and x-on:eventName="expression", shorthand is :attribute="expression" and @eventName="expression" respectively
  • Vue: v-bind:attribute="express" and v-on:eventName="expression", shorthand is :attribute="expression" and @eventName="expression" respectively

Rendering lists is achieved with x-for on a template element and conditional rendering with x-if on a template element.

Notice that Alpine.js doesn’t provide a full templating language, so there’s no interpolation syntax (e.g. in Vue.js, Handlebars and AngularJS). Instead, binding dynamic content is done with the x-text and x-html directives (which map directly to underlying calls to Node.innerText and Node.innerHTML).

An equivalent example using jQuery is an exercise you’re welcome to take on, but the classic style includes several steps:

  • Imperatively bind to the button click using $('button').click(/* callback */).
  • Within this “click callback” get the input value from the DOM, then use it to call the API.
  • Once the call has completed, the DOM is updated with new nodes generated from the API response.

If you’re interested in a side by side comparison of the same code in jQuery and Alpine.js, Alex Justesen created the same character counter in jQuery and in Alpine.js.

Back in vogue: HTML-centric tools

Alpine.js takes inspiration from TailwindCSS. The Alpine.js introduction on the repository is as “Tailwind for JavaScript.”

Why is that important?

One of Tailwind’s selling points is that it “provides low-level utility classes that let you build completely custom designs without ever leaving your HTML.” That’s exactly what Alpine does. It works inside HTML so there is no need to work inside of JavaScript templates the way we would in Vue or React  Many of the Alpine examples cited in the community don’t even use script tags at all!

Let’s look at one more example to drive the difference home. Here’s is an accessible navigation menu in Alpine.js that uses no script tags whatsoever.

This example leverages aria-labelledby and aria-controls outside of Alpine.js (with id references). Alpine.js makes sure the “toggle” element (which is a button), has an aria-expanded attribute that’s true when the navigation is expanded, and false when it’s collapsed. This aria-expanded binding is also applied to the menu itself and we show/hide the list of links in it by binding to hidden.

Being markup-centric means that Alpine.js and TailwindCSS examples are easy to share. All it takes is a copy-paste into HTML that is also running Alpine.js/TailwindCSS. No crazy directories full of templates that compile and render into HTML!

Since HTML is a fundamental building block of the web, it means that Alpine.js is ideal for augmenting server-rendered (Laravel, Rails, Django) or static sites (Hugo, Hexo, Jekyll). Integrating data with this sort of tooling can be a simple as outputting some JSON into the x-data="{}" binding. The affordance of passing some JSON from your backend/static site template straight into the Alpine.js component avoids building “yet another API endpoint” that simply serves a snippet of data required by a JavaScript widget.

Client-side without the build step

Alpine.js is designed to be used as a direct script include from a public CDN. Its developer experience is tailored for that. That’s why it makes for a great jQuery comparison and replacement: it’s dropped in and eliminates a build step.

While it’s not traditionally used this way, the bundled version of Vue can be linked up directly. Sarah Drasner has an excellent write-up showing examples of jQuery substituted with Vue. However, if you use Vue without a build step, you’re actively opting out of:

  • the Vue CLI
  • single file components
  • smaller/more optimized bundles
  • a strict CSP (Content Security Policy) since Vue inline templates evaluate expressions client-side

So, yes, while Vue boasts a buildless implementation, its developer experience is really depedent on the Vue CLI. That could be said about Create React App for React, and the Angular CLI. Going build-less strips those frameworks of their best qualities.

There you have it! Alpine.js is a modern, CDN-first  library that brings declarative rendering for a small payload — all without the build step and templates that other frameworks require. The result is an HTML-centric approach that not only resembles a modern-day jQuery but is a great substitute for it as well.

If you’re looking for a jQuery replacement that’s not going to force you into a SPAs architecture, then give Alpine.js a go! Interested? You can find out more on Alpine.js Weekly, a free weekly roundup of Alpine.js news and articles.

The post Alpine.js: The JavaScript Framework That’s Used Like jQuery, Written Like Vue, and Inspired by TailwindCSS appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/3aMMDvq
via IFTTT

Tuesday, 28 April 2020

How to Redirect a Search Form to a Site-Scoped Google Search

This is just a tiny little trick that might be helpful on a site where you don’t have the time or desire to build out a really good on-site search solution. Google.com itself can perform searches scoped to one particular site. The trick is getting people there using that special syntax without them even knowing it.

Make a search form:

<form action="https://google.com/search" target="_blank" type="GET">

  <label>
     Search CSS-Tricks on Google: 
     <input type="search" name="q">
   </label>

  <input type="submit" value="Go">

</form>

When that form is submitted, we’ll intercept it and change the value to include the special syntax:

var form = document.querySelector("form");

form.addEventListener("submit", function (e) {
  e.preventDefault();
  var search = form.querySelector("input[type=search]");
  search.value = "site:css-tricks.com " + search.value;
  form.submit();
});

That’s all.

The post How to Redirect a Search Form to a Site-Scoped Google Search appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2YqNEqL
via IFTTT

Using Formik to Handle Forms in React

There is no doubt that web forms play an integral role in our web site or applications. By default, they provide a useful set of elements and features — from legends and fieldsets to native validation and states — but they only get us so far when we start to consider the peculiarities of using them. For example, how can we manipulate the state of a form? How about different forms of validation? Even hooking a form up to post submissions is a daunting effort at times.

Component-driven front-end libraries, like React, can ease the task of wiring web forms but can also get verbose and redundant. That’s why I want to introduce you to Formik, a small library that solves the three most annoying parts of writing forms in React:

  1. State manipulation
  2. Form validation (and error messages)
  3. Form submission

We’re going to build a form together in this post. We’ll start with a React component then integrate Formik while demonstrating the way it handles state, validation, and submissions.

Creating a form as a React component

Components live and breathe through their state and prop. What HTML form elements have in common with React components is that they naturally keep some internal state. Their values are also automatically stored in their value attribute.

Allowing form elements to manage their own state in React makes them uncontrolled components. That’s just a fancy way of saying the DOM handles the state instead of React. And while that works, it is often easier to use controlled components, where React handles the state and serves as the single source of truth rather than the DOM.

The markup for a straightforward HTML form might look something like this:

<form>
  <div className="formRow">
    <label htmlFor="email">Email address</label>
    <input type="email" name="email" className="email" />
  </div>
  <div className="formRow">
    <label htmlFor="password">Password</label>
    <input type="password" name="password" className="password" />
  </div>
  <button type="submit">Submit</button>
</form>

We can convert that into a controlled React component like so:

function HTMLForm() {
  const [email, setEmail] = React.useState("");
  const [password, setPassword] = React.useState("");


  return (
    <form>
      <div className="formRow">
        <label htmlFor="email">Email address</label>
        <input
          type="email"
          name="email"
          className="email"
          value={email}
          onChange={e => setEmail(e.target.value)}
        />
      </div>
      <div className="formRow">
        <label htmlFor="password">Password</label>
        <input
          type="password"
          name="password"
          className="password"
          value={password}
          onChange={e => setPassword(e.target.value)}
        />
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

This is a bit verbose but it comes with some benefits:

  1. We get a single source of truth for form values in the state.
  2. We can validate the form when and how we want.
  3. We get performance perks by loading what we need and when we need it.

OK, so why Formik again?

As it is with anything JavaScript, there’s already a bevy of form management libraries out there, like React Hook Form and Redux Form, that we can use. But there are several things that make Formik stand out from the pack:

  1. It’s declarative: Formik eliminates redundancy through abstraction and taking responsibility for state, validation and submissions.
  2. It offers an Escape Hatch: Abstraction is good, but forms are peculiar to certain patterns. Formik abstracts for you but also let’s you control it should you need to.
  3. It co-locates form states: Formik keeps everything that has to do with your form within your form components.
  4. It’s adaptable: Formik doesn’t enforce any rules on you. You can use as less or as much Formik as you need.
  5. Easy to use: Formik just works.

Sound good? Let’s implement Formik into our form component.

Going Formik

We will be building a basic login form to get our beaks wet with the fundamentals. We’ll be touching on three different ways to work with Formik:

  1. Using the useFormik hook
  2. Using Formik with React context
  3. Using withFormik as a higher-order component

I’ve created a demo with the packages we need, Formik and Yup.

Method 1: Using the useFormik hook

As it is right now, our form does nothing tangible. To start using Formik, we need to import the useFormik hook. When we use the hook, it returns all of the Formik functions and variables that help us manage the form. If we were to log the returned values to the console, we get this:

Showing console output of the various hooks and objects that are logged by Formik.

We’ll call useFormik and pass it initialValues to start. Then, an onSubmit handler fires when a form submission happens. Here’s how that looks:

// This is a React component
function BaseFormik() {
  const formik = useFormik({
    initialValues: {
      email: "",
      password: ""
    },
    onSubmit(values) {
      // This will run when the form is submitted
    }
  });
  
 // If you're curious, you can run this Effect
 //  useEffect(() => {
 //   console.log({formik});
 // }, [])


  return (
    // Your actual form
  )
}

Then we’ll bind Formik to our form elements:

// This is a React component
function BaseFormik() {
  const formik = useFormik({
    initialValues: {
      email: "",
      password: ""
    },
    onSubmit(values) {
      // This will run when the form is submitted
    }
  });
  
 // If you're curious, you can run this Effect
 //  useEffect(() => {
 //   console.log({formik});
 // }, [])


  return (
  // We bind "onSubmit" to "formik.handleSubmit"
  <form className="baseForm" onSubmit={formik.handleSubmit} noValidate>
    <input
      type="email"
      name="email"
      id="email"
      className="email formField"
      value={formik.values.email} // We also bind our email value
      onChange={formik.handleChange} // And, we bind our "onChange" event.
    />
  </form>
  )
}

This is how the binding works:

  1. It handles form submission with onSubmit={formik.handleSubmit}.
  2. It handles the state of inputs with value={formik.values.email} and onChange={formik.handleChange}.

If you take a closer look, we didn’t have to set up our state, nor handle the onChange or onSubmit events as we’d typically do with React. The complete change to our form goes:

However as you might have noticed, our form contains some redundancy. We had to drill down formik and manually bind the form input’s value and onChange event. That means we should de-structure the returned value and immediately bind the necessary props to a dependent field, like this:

// This is a React component
function BaseFormik() {
  const {getFieldProps, handleSubmit} = useFormik({
    initialValues: {
      email: "",
      password: ""
    },
    onSubmit(values) {
      // This will run when the form is submitted
    }
  });
  
 // If you're curious, you can run this Effect
 //  useEffect(() => {
 //   console.log({formik});
 // }, [])


  return (
  <form className="baseForm" onSubmit={handleSubmit} noValidate>
    <input
      type="email"
      id="email"
      className="email formField"
      {...getFieldProps("email")} // We pass the name of the dependent field
    />
  </form>
  )
}

Let’s take things even further with the included <Formik/>  component.

Method 2: Using Formik with React context

The <Formik/> component exposes various other components that adds more abstraction and sensible defaults. For example, components like <Form/>, <Field/>, and <ErrorMessage/> are ready to go right out of the box.

Keep in mind, you don’t have to use these components when working with <Formik/> but they do require <Formik/> (or withFormik) when using them.

Using <Formik/> requires an overhaul because it uses the render props pattern as opposed to hooks with useFormik. The render props pattern isn’t something new in React. It is a pattern that enables code re-usability between components — something hooks solve better. Nevertheless, <Formik/> has a bagful of custom components that make working with forms much easier.

import { Formik } from "formik";


function FormikRenderProps() {
  const initialValues = {
    email: "",
    password: ""
  };
  function onSubmit(values) {
    // Do stuff here...
    alert(JSON.stringify(values, null, 2));
  }
  return (
      <Formik {...{ initialValues, onSubmit }}>
        {({ getFieldProps, handleSubmit }) => (
            <form className="baseForm" onSubmit={handleSubmit} noValidate>
              <input
                type="email"
                id="email"
                className="email formField"
                {...getFieldProps("email")}
              />
            </form>
        )}
      </Formik>
  );
}

Notice that initialValues and onSubmit have been completely detached from useFormik. This means we are able to pass the props that <Formik/> needs, specifically initialValues and useFormik.

<Formik/> returns a value that’s been de-structured into getFieldProps and handleSubmit. Everything else basically remains the same as the first method using useFormik.

Here’s a refresher on React render props if you’re feeling a little rusty.

We haven’t actually put any <Formik/> components to use just yet. I’ve done this intentionally to demonstrate Formik’s adaptability. We certainly do want to use those components for our form fields, so let’s rewrite the component so it uses the <Form/> component.

import { Formik, Field, Form } from "formik";


function FormikRenderProps() {
  const initialValues = {
    email: "",
    password: ""
  };
  function onSubmit(values) {
    // Do stuff here...
    alert(JSON.stringify(values, null, 2));
  }
  return (
      <Formik {...{ initialValues, onSubmit }}>
        {() => (
            <Form className="baseForm" noValidate>
              <Field
                type="email"
                id="email"
                className="email formField"
                name="email"
              />
            </Form>
        )}
      </Formik>
  );
}

We replaced <form/> with <Form/> and removed the onSubmit handler since Formik handles that for us. Remember, it takes on all the responsibilities for handling forms.

We also replaced <input/> with <Field/> and removed the bindings. Again, Formik handles that.

There’s also no need to bother with the returned value from <Formik/> anymore. You guessed it, Formik handles that as well.

Formik handles everything for us. We can now focus more on the business logic of our forms rather than things that can essentially be abstracted.

We’re pretty much set to go and guess what? We’ve haven’t been concerned with state managements or form submissions!

“What about validation?” you may ask. We haven’t touched on that because it’s a whole new level on its own. Let’s touch on that before jumping to the last method.

Form validation with Formik

If you’ve ever worked with forms (and I bet you have), then you’re aware that validation isn’t something to neglect.

We want to take control of when and how to validate so new opportunities open up to create better user experiences. Gmail, for example, will not let you input a password unless the email address input is validated and authenticated. We could also do something where we validate on the spot and display messaging without additional interactions or page refreshes.

Here are three ways that Formik is able to handle validation:

  1. At the form level
  2. At the field level
  3. With manual triggers

Validation at the form level means validating the form as a whole. Since we have immediate access to form values, we can validate the entire form at once by either:

Both validate and validationSchema are functions that return an errors object with key/value pairings that those of initialValues. We can pass those to  useFormik, <Formik/> or withFormik

While validate is used for custom validations, validationSchema is used with a third-party library like Yup. 

Here’s an example using validate:

// Pass the `onSubmit` function that gets called when the form is submitted.
const formik = useFormik({
  initialValues: {
    email: "",
    password: ""
  },
  // We've added a validate function
  validate() {
    const errors = {};
    // Add the touched to avoid the validator validating all fields at once
    if (formik.touched.email && !formik.values.email) {
      errors.email = "Required";
    } else if (
      !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(formik.values.email)
    ) {
      errors.email = "Invalid email address";
    }
    if (formik.touched.password && !formik.values.password) {
      errors.password = "Required";
    } else if (formik.values.password.length <= 8) {
      errors.password = "Must be more than 8 characters";
    }
    return errors;
  },
  onSubmit(values) {
    // Do stuff here...
  }
});
// ...

And here we go with an example using validationSchema instead:

const formik = useFormik({
  initialValues: {
    email: "",
    password: ""
  },
  // We used Yup here.
  validationSchema: Yup.object().shape({
    email: Yup.string()
      .email("Invalid email address")
      .required("Required"),
    password: Yup.string()
      .min(8, "Must be more than 8 characters")
      .required("Required")
  }),
  onSubmit(values) {
    // Do stuff here...
  }
});

Validating at the field level or using manual triggers are fairly simple to understand. Albeit, you’ll likely use form level validation most of the time. It’s also worth checking out the docs to see other use cases.

Method 3: Using withFormik as a higher-order component

withFormik is a higher-order component and be used that way if that’s your thing. Write the form, then expose it through Formik.

A couple of practical examples

So far, we’ve become acquainted with Formik, covered the benefits of using it for creating forms in React, and covered a few methods to implement it as a React component while demonstrating various ways we can use it for validation. What we haven’t done is looked at examples of those key concepts.

So, let’s look at a couple of practical applications: displaying error messages and generating a username based on what’s entered in the email input.

Displaying error messages

We’ve built our form and validated it. And we’ve caught some errors that can be found in our errors object. But it’s no use if we aren’t actually displaying those errors.

Formik makes this a pretty trivial task. All we need to do is check the errors object returned by any of the methods we’ve looked at — <Formik/>, useFormik or withFormik — and display them:

<label className="formFieldLabel" htmlFor="email">
  Email address
  <span className="errorMessage">
    {touched["email"] && errors["email"]}
  </span>
</label>
<div className="formFieldWrapInner">
  <input
    type="email"
    id="email"
    className="email formField"
    {...getFieldProps("email")}
  />
</div>

If there’s an error during validation, {touched["email"] && errors["email"]} will display it to the user.

We could do the same with <ErrorMessage/>. With this, we only need to tell it the name of the dependent field to watch:

<ErrorMessage name="email">
  {errMsg => <span className="errorMessage">{errMsg}</span>}
</ErrorMessage>

Generating a username from an email address

Imagine a form that automatically generates a username for your users based on their email address. In other words, whatever the user types into the email input gets pulled out, stripped of @ and everything after it, and leaves us with a username with what’s left.

For example: jane@doe.com produces @jane.

Formik exposes helpers that can “intercept” its functionality and lets us perform some effects.In the case of auto-generating a username, one way will be through Formik’s setValues:

onSubmit(values) {
  // We added a `username` value for the user which is everything before @ in their email address.
  setValues({
    ...values,
    username: `@${values.email.split("@")[0]}`
  });
}

Type in an email address and password, then submit the form to see your new username!

Wrapping up

Wow, we covered a lot of ground in a short amount of space. While this is merely the tip of the iceberg as far as covering all the needs of a form and what Formik is capable of doing, I hope this gives you a new tool to reach for the next time you find yourself tackling forms in a React application.

If you’re ready to take Formik to the next level, I’d suggest looking through their resources as a starting point. There are so many goodies in there and it’s a good archive of what Formik can do as well as more tutorials that get into deeper use cases.

Good luck with your forms!

The post Using Formik to Handle Forms in React appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/3bL6hth
via IFTTT

Monday, 27 April 2020

Static or Not?

A quick opinion piece by Kev Quirk: Why I Don’t Use A Static Site Generator. Kev uses WordPress:

Want to blog on my iPad? I can. Want to do it on my phone? No problem. On a machine I don’t normally use? Not an issue, as long as it has a browser.

First, it’s worth understanding that by using WordPress it doesn’t opt you out of using a static site generator. WordPress has an API, and that opens the door to hit that API during a build process and build your site that way. That’s what Gatsby does, there is a plugin that exports a static site, and projects like Frontity really blur the lines.

But I agree with Kev here on his reasoning. For all his reasons, and 1,000 more, it’s a perfectly acceptable and often smart choice to run a WordPress site. I think about it in terms of robustness and feature-readiness. Need e-commerce? It’s there. Need forms? There are great plugins. Need to augment how the CMS works? You have control over the types of content and what is in them. Need auth? That’s a core feature. Wish you had a great editing experience? Gutenberg is glorious.

Time and time again, I build what I wanted to build with WordPress quickly and efficiently and it’s made me feel productive and powerful. But I don’t wanna make this specifically about WordPress; this can be true of any “classic” CMS. Craft CMS has a GraphQL API out of the box. We just posted about a Drupal + Jamstack webinar.

In the relatively new world of static sites, a little thing can end up a journey of research and implementation, like you’re the only third person on Earth to ever do it.

Now all that said…

What do I think of static site generators and the Jamstack world? They are awesome.

I think there is a lot to be said about building sites this way. The decoupling of data and front-end is smart. The security is great. The DX, what with the deploy previews and git-based everything is great. The speed you get out of the gate is amazing (serving HTML from a CDN is some feat).

Just like a classic server-side CMS doesn’t opt you out of building a static site, building with a static site doesn’t opt you out of doing dynamic things — even super duper fancy dynamic things. Josh Comeau has a great new post going into this. He built a fancy little app that does a ton in the browser with React, but that doesn’t mean he still can’t deliver a good amount of it statically. He calls it a “mindset shift,” referring to the idea that you might think you need a database call, but do you really? Could that database call have already happened and generated a static file? And if not, still, some of it could have been generated with the last bits coming over dynamically.

I can’t wait for a world where we start really seeing the best of both worlds. We do as much statically as possible, we get whatever we can’t do that way with APIs, and we don’t compromise on the best tools along the way.

When to go with a static site…

  • If you can, you should consider it, as the speed and security can’t be beaten.
  • If you’re working with a Greenfield project.
  • If your project builds from and uses accessible APIs, you could hit that API during the build process as well as use it after the initial HTML loads.
  • If some static site generator looks like a perfect fit for something you’re doing.
  • If a cost analysis says it would be cheaper.
  • If functionality (like build previews) would be extremely helpful for a workflow.

When to go with server-side software…

  • If you need the features of a classic CMS (e.g. WordPress), and the technical debt of going static from there is too high.
  • If you’re already in deep with a server-rendered project (Ruby on Rails, Python, etc.) and don’t have any existing trouble.
  • If that is where you have the most team expertise.
  • If a cost analytics says it would be cheaper.
  • If there aren’t good static solutions around for what want to build (e.g. forums software).
  • If you have an extreme situation, like millions of URLs, and the build time for static is too high.

Bad reasons to avoid a static site…

  • You need to do things with servers. (Why? You can still hit APIs on servers, either at build or during runtime.)
  • You need auth. (Why? Jamstack is perfectly capable of auth with JWTs and such.)
  • You haven’t even looked into doing things Jamstack-style.

Bad reasons to choose server-side software…

  • You haven’t even looked into doing things Jamstack-style.
  • Because you think using comfortable / existing / classic / well-established / well-supported tools opt you out of building anything statically.
  • Something something SEO. (If anything, statically rendered content should perform better. But it’s understandable if a move to static means moving to client-side calls for something like product data.)

The post Static or Not? appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2xdDezr
via IFTTT

Advice for Writing a Technical Resume

Marco Rogers asked a very good question on Twitter:

I’ve been on both sides of the interview table for many years now, both searching for jobs and as a hiring manager. My resume skills and most salient advice for writing one is likely from my experiences looking though thousands of applications.

When it comes to writing a resume, It’s helpful to think about the human aspect first and foremost. Imagining a hiring manager’s perspective will give you an edge because it helps speak to them directly. Remember, a coveted position or reputable company commonly sifts through anywhere between tens and thousands of applications. It takes a staff that is materially impacted in the time and energy it takes to review every candidate and evaluate those who make it in to the interview stage. Even attention to minor details will help your odds of standing out.

Here are my general suggestions to make the best possible resume.

Formatting is important

Spelling, grammar and formatting are all crucial to a well-written resume. Typos, errors, and poor use of things like bold and italic styles (especially when used together) are clear red flags, so pay extra attention to what you write and how it is written. These types of mistakes give the impressions that you either lack attention to detail or are unwilling to go the extra step. As trivial as this might seem, use your spell check and get a second set of eyes on your resume before submitting it.

A few formatting tips to keep in mind:

  • Use headings to separate sections
  • Use lists to help summarize highlights and things scannable
  • Use a good font and font size that makes the content legible
  • Use line spacing that lets content breath rather than packing it close together
  • Avoid using all caps, or combining bold, italic, and underlines on the same content.

I don’t have a strong opinion on charts that show off your skills or lists of hobbies. But I will say that I’ve noticed them more frequently on the applications of junior developers, so you might unintentionally communicate you have less experience by including it.

If you don’t have a lot of work history, it’s totally OK to throw in open source projects!

Or side projects! Or working on your own site! A few folks mentioned the same thing in the Twitter thread and it’s solid advice. A good hiring manager should know that senior-level candidates don’t grow on trees — they just want to see some work that shows you have promise.

This is problematic advice in some ways, as not everyone has time on the side to devote to projects. I wouldn’t so far as to say including those things is a hard requirement for a good resume. But if you’re otherwise lacking relevant work experience, including personal projects can show the kind of work you’re capable of doing as well as the kind of work that excites you. I’ve taken chances on folks with slim-to-no work experience but with a solid combination of a portfolio site, GitHub contributions, or even a few CodePen demos that show potential.

Call out your contributions to your work experience

Each time you list a work example, answer this: what did you accomplish? This is a good way to provide valuable information without or any unnecessary fluff. Everyone is going to tout their work experience. Adding the outcomes of your work will make you stand out.

Here’s an example that would catch my attention:

Due to my team’s work refactoring the product page, we were able to meet the demands of our customers, which resulted in a 25% growth in sales. We also took the opportunity to upgrade the codebase from React.createClass to React Hooks for all of our components, ensuring a more flexible and maintainable system.

This tells me you can work on a team to deliver goals. It also tells me that you understand technical debt and how to solve it. That’s the sort of person I want to hire.

If so far your experience is limited to a code bootcamp, it’s great to talk through that.

Every job applicant is coming from a different background and from varying degrees of experience. It’s safe to assume you are not the most experienced person in the pool.

And that’s OK!

For example, let’s say your development experience is limited to online or in-person coding bootcamps rather than commercial projects. What did you learn there? What were you excited by? What was your final project? Is there a link to that work? When I’m hiring someone who’s coming in early in their career, I’m mostly looking for curiosity and enthusiasm. I’m probably not alone there.

Don’t be too long… or too short

We mentioned earlier that hiring is a time-consuming job. It’s good to keep this in mind as you’re writing by making your resume as brief as possible — ideally on a single standard page. And, yes, two pages is OK if you really need it.

Keeping everything short is a balancing act when you’re also attempting to include as much useful information as possible. Treat that constraint as a challenge to focus on the most important details. It’s a good problem if you have more to say than what fits!

At best, padding a resume into multiple pages conveys you’re unable to communicate in a succinct manner. At worst, it shows a lack of respect for a hiring manager’s time.

Make sure there’s a way to reach you

I cannot tell you how many resumes that lack the following essentials: name, email, and phone number. Seriously, it happens even on resumes that are otherwise very impressive.

Your name and contact information are hard requirements. I don’t want to search around for your email if you’re applying. To be honest, I probably won’t search at all because I’m busy and there are many other candidates to choose from.

Preparation is your friend

Make sure your accompanying cover letter (yes, you should include one) communicates you’ve done at least a little research on the company, conveys you understand what they need in a candidate, and how you fit into that need.

I will personally adjust my the descriptions in my own resume so there is a direct connection between my skills and the position.

Your work and education details should be reverse-chronological

Your most recent work is more important than your oldest work. It’s a better reflection of what you’re capable of doing today and how fresh your skills are in a particular area. The same goes for your education: lead with your most recent experience.

The person reviewing your resume can decide to continue reading further if they’re compelled by the most recent information.

Wrapping up

If you want to stand out in the crowd, make sure your resume is one that represents you well. Ask someone to help you proof and use spellcheck, and make sure you’ve put your best foot forward.

And don’t be discouraged by rejections or unreturned messages. It’s less likely to be about you personally and more likely due to the number of people applying. So keep trying!

The post Advice for Writing a Technical Resume appeared first on CSS-Tricks.



from CSS-Tricks https://ift.tt/2ySyiAf
via IFTTT

What Readers Want During COVID-19: B2B Edition

Posted by amandamilligan

I couldn’t believe the response to my last post about coming up with content ideas in the B2C space during COVID-19. Thank you to all who read and commented — I truly hope it was helpful.

One piece of feedback we received was an ask to see some B2B content ideas, which, frankly, is an excellent subject. At first I was stumped about how to determine this, but then I decided that a different tool could do the trick.

Exploding Topics, the new tool by Brian Dean (Backlinko) and Josh Howarth, explores topics that are surging in popularity but haven’t hit their peak.

This time around, rather than focusing on specific keywords, I focused on overall trends so we can identify which categories might be of interest to your target businesses and their audiences. Then, you can examine whether these trends make sense for your niche and draw inspiration from them for your content.

All things remote

This trend obviously applies to B2C as well, but it’s an important consideration for B2B. Nearly everything has been either canceled, paused, or moved into the world of the virtual. For many companies and industries, this is uncharted territory, and they need guidance.

There is another category I could have included here that focuses on website and app development, programming, and the open source tools that help people build those types of assets as they lean more into digital.

If you’re not one of these B2B providers, there are still ways to gain inspiration from this data. Consider if your brand can provide:

  • The logistics of how to set up remote platforms
  • Best practices on how to make anything remote more successful and engaging
  • Comparison guides for different tools and solutions
  • The platform for people to lend the help and support they’re hoping to (like in the case of virtual tip jars)
  • Communication tips and solutions to help people stay productively connected

Shipping and delivery

Consumers are interested in having things shipped directly to them, but not everyone has the infrastructure to deal with shipping to begin with, let alone an increased order volume with the (understandable) safety limitations now in place.

Consumers and businesses alike are curious about how to make the shipping and delivery process more effective.

Consider if your brand can provide:

  • Guides for small businesses who’ve never had to ship product before
  • Tips on how companies can message shipping updates and delays to consumers
  • Advice on how to improve the delivery component of a business
  • UX or language tips for updating delivery messaging in apps or on websites

Transactions and payment

As we’re all staying six feet away from each other, we’re also trying not to hand off credit cards (let alone cash). Companies used to brick-and-mortar business models are also needing to adapt to fully digital payment systems.

Not all of these searches apply to business (like Venmo), but they do point to a concern everyone’s having: How do we pay for things now?

Consider if your brand can provide:

  • Answers about privacy or security questions people have regarding digital payments
  • A detailed list of all the payment options available
  • Advice on how to optimize storefronts and purchasing processes
  • Explanations of how payment processes can impact sales, and how to optimize them

Design tools

This section speaks to an overall trend I touched on before: Professionals now build their own assets if they can’t afford to hire web developers, designers, etc. More and more people are trying to figure out how to keep their businesses going when they can’t keep on as much staff or hire as many contractors.

Perhaps you can identify what your target audience might be struggling with and suggest free or inexpensive online tools to help.

Consider if your brand can provide:

  • A list of tools that can assist your target audience in communicating, organizing, creating, etc.
  • Design advice to help them get up to speed as quickly as possible
  • Resources in how to complete tasks on a smaller team
  • Recommendations for what should be prioritized when money is tight

Ethical trends

This is perhaps the most fascinating trend I saw arise. The four brands below have something in common: they all have to do with either sustainability or a transparent, mission-driven approach.

My theory is now that people don’t have as much disposable income, they’re becoming more mindful in their shopping choices, selecting items they believe match their own values.

Consider if your brand can provide:

  • A greater level of analysis on this potential trend
  • Research into how the consumer perspective has shifted during COVID-19
  • Advice on how to potentially shift marketing, branding, and advertising messaging
  • Tips on how your target audience can better understand their marketing during this tumultuous time

And finally (*sigh of relief*), marketing

Yes, as I was doing my research, my instinct that marketing would remain crucial during this time was confirmed.

That doesn’t mean you won’t lose business. We’ve had clients pull back because even though they’d like to keep marketing, keeping the company afloat by fulfilling their product orders and services and paying their employees will always (and very understandably) come first by a long shot.

But for businesses that can still afford marketing, they’ll likely need it, and they’re looking for the tools and insight they need to thrive.

Consider if your brand can provide:

  • Marketing 101 tips for smaller businesses
  • Specific how-to guides for different aspects of inbound or outbound marketing
  • Tool recommendations to help people get marketing tasks done quickly and cheaply
  • Advice on the kind of marketing that’s most successful during an economic downturn

Conclusion

Remember: This is only for inspiration. What matters most is what your target audience needs and wants. Put yourself in their shoes to be able to best address their challenges and concerns.

But hopefully some of these concepts spark some ideas for how your B2B brand can provide value to your target audiences. Companies around the world are looking for guidance and support now more than ever, and if you’re in a position to provide it to them, your content can go a long way in building trust.


Sign up for The Moz Top 10, a semimonthly mailer updating you on the top ten hottest pieces of SEO news, tips, and rad links uncovered by the Moz team. Think of it as your exclusive digest of stuff you don't have time to hunt down but want to read!



from The Moz Blog https://ift.tt/2KEJbZ7
via IFTTT

Passkeys: What the Heck and Why?

These things called  passkeys  sure are making the rounds these days. They were a main attraction at  W3C TPAC 2022 , gained support in  Saf...