Today I Learned

Small clippings of things I’ve learned. Not always learned on the day posted.


Add a quick GUI to a CodePen or other project with dat.GUI


TAGS: javascript

I've seen this GUI pop up all over CodePen, but for some reason never figured it was a little library. I'll use this on future CodePens to change different attributes and make it more interactive.


I wonder if this could be brought into design system pages to add some Storybook-like interactivity to components.


Add spacing above jump links on pages


TAGS: css

If you have a fixed header and try to link down the page, you often find the header gets eaten by the header. I've messed with this before and tried to find solutions with hacky JS scrolls or padding. Turns out there's a built in solution for this.

h3 {
  scroll-margin-top: 5rem; /* whatever is a nice number that gets you past the header */

This shouldn't affect the look of the site, just where you scroll to if you have this:

<a href="#pets">Scroll to pets</a>


<h2 name="pets">Pets</h2>

Learned this from this CSS Tricks article.


Easily Generate CraftCMS Modules


TAGS: craftcms

When I needed to create a new module for a CraftCMS build we're working on, my coworker Dan Poulin showed me a great resource. It's something that I'll reference for many months to come, so it'll work great as a TIL.

Head to Plugin and fill out what you need. Generate the module and follow the README you get in the zip file.


Run Multiple Terminal Commands at the Same Time with Concurrently


TAGS: terminal

I've always opened two terminals to run a backend and frontend locally. It's not the worst thing in my workflow, but I love finding things to make it all a little smoother. Concurrently is an npm package that lets you run any commands at the same time.

Like npm run watch-js & npm run watch-less but better.

From their example: concurrently "npm:watch-js" "npm:watch-css" "npm:watch-node"

Learned this from Brad Traversy while watching his GraphQL series -


Adding Aliases for Bash


TAGS: terminal

I noticed I was repeating the same set of actions over and over which means it's time to automate. Let's use an Alias.

It's pretty simple:

alias stashpull='git stash && git pull -r && git stash pop'

Now I just type stashpull and it fires off three commands quickly.


Snapshot DynamoDB Objects


TAGS: problem solving

Working on the Onboarding flow of an app can be tricky. With a lot of different properties to keep track of, it's tough to get back to a specific point in time with manual editing.

It might seem obvious, but copying the entire JSON object and saving it in a .json file after each change lets me time-travel back to different states.

I created a folder with a and 1.json for the object on init, then added json files for each change.

This helps in a few ways. It made it easy to diff changes that were creating bugs. I can also rewind this object back to start, which is helpful while creating something very state-driven, like an onboarding flow.


The Most Important Role of JS Frameworks


TAGS: reactvuejavascript

My friend Pete passed along this article: The deepest reason why modern JavaScript frameworks exist. Granted, the title is a little questionable, but the thesis raised a good point.

The main problem modern JavaScript frameworks solve is keeping the UI in sync with the state.

So when should you reach for a React or Vue? When you need to keep the state and the UI in sync.

If you don't have state, or the state isn't changing you can get by with Vanilla JS. Anything more, and you're probably better off pulling in React or Vue.


Locally Host Fonts Easily with Typeface npm Package


TAGS: gatsbyfonts

Turns out "self-hosting" web fonts is much faster than using Google or Adobe's CDN.

You can put the font file into your assets folder in a Gatsby project, and that'll work just fine.

I opted to use this npm package called Typefaces by Gatsby's Kyle Mathews. Trusted source and all that.

More importantly, I didn't have to go and track down the font files I wanted to use.

Setup for Gatsby

In your terminal:

yarn add typeface-open-sans typeface-raleway

Then in gatsby-browser.js


All set. Gatsby will even put the CSS in my <head> so it all loads faster.


Hiding Content with Summary/Details HTML Elements


TAGS: html

Reading through Chris Coyier's excellent Advice for Technical Writing I saw him mention the details and summary elements.

Basically a native browser way to tuck some text away into an accordion.

Here's his example from the article:

  <summary>What is the population of New Orleans?</summary>
  <p>According to 2010 Census Bureau estimates, New Orleans' population is made up of approximately 343,829 residents.</p>

This seems like a great way to make a self-administered 'quiz' for your readers as a review at the end of an article.


In the article, Chris seems to recommend the details element to make text opt-in, rather than all visible.

Maybe if you're writing an article and you mention Redux. You don't want to bore the readers who already know it, but also don't want to leave behind readers who don't.

Tucking it away in a details or summary element gives both readers what they need.


Referencing Angular controls with dot notation


TAGS: angular

Sometimes when referencing a specific control in an Angular 2+ FormControl, VSCode will claim that it can't find controls on personalForm in your template.

Here's an easy fix to appease the IDE Gods:

- [errors]="myForm.controls.firstName.errors ? myForm.controls.firstName.errors : []"
+ [errors]="myForm['controls'].firstName.errors ? myForm['controls'].firstName.errors : []"

Easy console.log in Arrow Functions


TAGS: javascript

Generally if I want to log out what's getting passed into an arrow function like this:

const newNames = name => doThing(name) )

I have to add brackets and a return like this:

const newNames = name =>  {
  return doThing(name);

But because console.log()'s value is void, the || (OR) operator will run the function, and because it's falsey, return the second thing, like this:

const newNames = name => console.log(name) || doThing(name) )

TypeScript yells at you saying console.log() will never resolve as true. But we're not shipping the code, just debugging. It works just fine for that.

Thanks to my coworker Brendan for showing me this trick.


Remove Unused Imports with TypeScript and VSCode


TAGS: vscodetypescriptjavascript

When refactoring I'll typically remove some code and have some unused imports sitting at the top of my files. Going in and sniping out each faded word isn't the best use of time, so let's let our IDE take care of it.

VSCode has an Organize Imports feature that allows you to clean up your code with a keystroke.

option+Shift+O for Mac

Alt + Shift + O for Windows

Not only that, but it reorganizes the imports alphabetically, leaving you with clean code that your whole team can agree on.

I'd love to see this kind of thing roped into Prettier so that my code gets cleaned up all in one fell swoop.

Learned this after a search and StackOverflow result.


Shadowing Gatsby Themes


TAGS: gatsby

I'm adding Gatsby-Theme-Notes to my personal site and had trouble wrapping it in my site's layout component.

I found Chris Bascardi's blog post on Layouts in Gatsby Themes but it didn't specifically say how to wrap the theme in my layout component.

I did some digging and watched Jason Lengstorf and Brent Jackson go through a theme. Turns out they needed to shadow the Gatsby theme they were using.

We do this by creating a folder in our project that's named the same as the folder in the theme. Whatever files or components we want to overwrite we include in that folder.

It's kind of like using the spread operator to overwrite a property.

const newFirstName = "Sarah";
const newUser = { ...oldUser, firstName: newFirstName };

Anything that's in the theme's src folder we can shadow.

The theme's file structure looks like this:

📦 gatsby-theme-notes
 ┣ 📂src
 ┃ ┣ 📂components
 ┃ ┃ ┣ 📜breadcrumb-divider.js
 ┃ ┃ ┣ 📜breadcrumb-home.js
 ┃ ┃ ┣ 📜breadcrumbs.js
 ┃ ┃ ┣ 📜directory-list.js
 ┃ ┃ ┣ 📜file-list.js
 ┃ ┃ ┣ 📜footer.js
 ┃ ┃ ┣ 📜layout.js
 ┃ ┃ ┣ 📜note.js
 ┃ ┃ ┗ 📜notes.js
 ┃ ┣ 📂gatsby-plugin-theme-ui
 ┃ ┃ ┗ 📜index.js
 ┃ ┣ 📂templates
 ┃ ┃ ┣ 📜note.js
 ┃ ┃ ┗ 📜notes.js
 ┃ ┣ 📜use-options.js
 ┃ ┗ 📜use-site-metadata.js
 ┣ 📜
 ┣ 📜gatsby-config.js
 ┣ 📜gatsby-node.js
 ┣ 📜index.js
 ┗ 📜package.json

So to shadow the layout component, my file structure looks like this:

 ┣ 📂gatsby-theme-notes
 ┃ ┣ 📂components
 ┃ ┃ ┣ 📜layout.js

Gatsby will use my layout component in place of the Theme's, but keep the rest of the theme's files. This lets me get updates to the project when they come in, as I'm only editing the one layout.js.


Subscribe to Action Results in NGRX with Facade Pattern


TAGS: angularngrx

At work we recently moved our state management to ngrx with a Facade pattern.

The developer who selected and implemented our facade pattern told us that it was impossible to know whether a call was successful or not. With a new hire at work and some Googling, we found a solution that works for the short term.

This response on Stack Overflow worked for the most part, but seemed to be using a different version of ngrx. Putting the methods inside a pipe made it work:

import { Actions } from '@ngrx/effects';

class SomeComponent implements OnDestroy {
    destroyed$ = new Subject<boolean>();

    constructor(updates$: Actions) {
+            .pipe(
+            ofType(PostActions.SAVE_POST_SUCCESS),
+            takeUntil(this.destroyed$),
+            tap((arg) => console.log(arg))
+            ).subscribe();
-            .ofType(PostActions.SAVE_POST_SUCCESS)
-            .takeUntil(this.destroyed$)
-            .do(() => /* hooray, success, show notification alert ect.. */)
-            .subscribe();

    ngOnDestroy() {

We'll eventually abstract this away into a class that our components can extend, but this is great for now.


Using LocalStorage for Quick Persistent State


TAGS: javascript

LocalStorage is handy in a pinch when you don't have any better solution for saving some form of state between sessions.

In my arcade game Dogger I save the scores to Local Storage so the user can compete against their personal best. LocalStorage is also handy for persisting a user's preference for Dark Mode, if your site offers it.

LocalStorage Methods

LocalStorage comes with a few methods to help us out.

Set Item

localStorage.setItem('highScore', '1500');

Get Item

To retrieve the data from localStorage:

const highScore = localStorage.getItem('highScore');

Remove Item


Clear Everything

This removes everything from localStorage on this current website. This won't affect the localStorage from other sites.


Using with LocalHost

You'll run into an issue when developing locally, as localStorage is all domain based. It helps if you make your key specific to the account or project you're on.

So instead of just doing:

localStorage.setItem('highScore', '1500');

You'd do something like this:

localStorage[] = JSON.stringify({ highScore : 1500 });

CSS Selectors: Child vs. Recursive


TAGS: css

For a while I thought there was little difference between div > div and div div in CSS. Turns out there's a pretty drastic difference.

All Child Elements

.container * {
  padding: 1rem;

That will affect all items recursively inside .container. Children, grandchildren, great-grandchildren. You get the idea.

First Level Only

.container > * {
  padding: 1rem;

That will only affect the first level of elements inside container. Just the children, leaving grand-children untouched.


Gatsby Clean


TAGS: gatsby

If you're having build trouble with Gatsby a lot of times clearing your .cache and public folders will fix the problem. There's even a Gatsby CLI shortcut to help with that.

gatsby clean

If you're still having trouble, try removing the node_modules folder and reinstalling npm packages.

Also make sure you're not mixing yarn and npm for managing your Gatsby project. It can quickly get messy.


VSCode Color Coded Title Bars


TAGS: vscode

If you have to switch between repositories multiple times a day, you might benefit from having your workspaces color coded. Blue for me is the UI, while our services code is orange, etc.

In the root of your project make a folder named .vscode. Inside create a settings.json file. Paste the following:

  "workbench.colorCustomizations": {
    "titleBar.activeBackground": "#34ace0",
    "titleBar.activeForeground": "#ffffff",
    "titleBar.inactiveBackground": "#368fb5",
    "titleBar.inactiveForeground": "#d7d7d7"

This will give you a nice skyblue titlebar. Change the colors and repeat the process in any repo you work in to give you a nice visual cue.

Picked this one up from Wes Bos's Advanced React course a while back. Still appreciate the visual cue every day.


Contentful, Gatsby, and Markdown


TAGS: graphqlgatsbycontentful

When adding this TIL feature to my website I hit a snag on build in gatsby-node.

The issue came because I'm bringing in data from local markdown files as well as the Contentful API. I have a markdown content type from Contentful that gets picked up by allMarkdownRemark. That would then try and access frontmatter that wasn't there. A quick filter in my GraphQL query allowed me to only bring in local files.

    filter: { fileAbsolutePath: { ne: null } }
  ) {
    edges {
      node {
        fields {
        frontmatter {
  allContentfulTil {
    edges {
      node {

Debugging Gatsby in VSCode


TAGS: vscodegatsbydebugging

I never realized just how nice the VSCode debugging was. Was having trouble debugging my Gatsby build and found these docs:

Setting VSCode's debug settings to Auto Attach and running this:

node --nolazy --inspect-brk node_modules/.bin/gatsby develop

I set up some breakpoints in the code, then I was able to see what was coming through and debug from there. Way more powerful than console logging out everything.


Angular Components with Top/Bottom Spacing


TAGS: angularcss

When trying to add top or bottom margin to an Angular component it has no effect unless you add display:block; to the component. Angular components default to display:inline which doesn't take top or bottom padding/margin.

Non-working example:

<my-component class="component"></my-component>
.component {
  margin: 2rem 0;

This has no effect because my-component is defaulting to display:inline.

Working example:

<my-component class="component"></my-component>
.component {
  margin: 2rem 0;

Avoiding Undefined in Deeply Nested Objects


TAGS: javascript

The Problem

When checking for a property on a heavily nested object, you can sometimes run into undefined errors.

It's not so bad with something like You can use the && operator like this:

user &&

This only tries to access name on user if user exists.

With this object: there are multiple points where it could all fall apart. The solution using && starts to get really messy.

Destructuring Solution

We can use destructuring assignment to pull the values out.

const { user: { company: { documents: { handbook:  = 'default' } = {} } = {} } = {} } } = this

This gives us fallbacks with each = {} and also makes the variables more managable to work with.

Learned this one from Brady Sutton.

Lodash Solution

Lodash gives us the get method where you pass it an object, then the path you want, then the default value you'd like returned if anything comes back undefined.

_.get(this, '', 'default')

Learned this one from Brady Sutton.

Optional Chaining Solution

We have a great solution coming to JavaScript soon called Optional Chaining. This will open up this syntax:


Naming CSS Grid Rows and Columns


TAGS: csscss grid

I usually name my CSS Grid areas so I can reference them easily. If I want to name columns I usually do it like this.

.container {
  display: grid;
  grid-template-columns: 3fr 4fr;
  grid-areas: "sidebar content";

Turns out there’s a great shorthand if you want to name an entire column or row. You can name your CSS Grid columns and rows like this:

.container {
  display: grid;
  grid-template-columns: [sidebar] 3fr [content] 4fr;

Not only does it save you some lines of code, but you get the name right next to the size for easy reference.

Learned it from this article.