{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "falldowngoboone",
  "language": "en",
  "home_page_url": "https://www.falldowngoboone.com/",
  "feed_url": "https://www.falldowngoboone.com/feed/feed.json",
  "description": "The ramblings of Ryan Boone, a web developer and designer from Texas with a passion for open, accessible front end development.",
  "author": {
    "name": "Ryan Boone",
    "url": "https://www.falldowngoboone.com/"
  },
  "items": [{
      "id": "https://www.falldowngoboone.com/blog/year-end-review-2025/",
      "url": "https://www.falldowngoboone.com/blog/year-end-review-2025/",
      "title": "Year-end review 2025",
      "content_html": "<p><strong>Another year, another review.</strong></p>\n<p>It’s the time of the year again where I actually contribute to my blog. 2025 was a roller coaster for me, and I honestly don’t know where to begin.</p>\n<p>So I’ll begin with a story.</p>\n<h2 id=\"joy-and-grief\" tabindex=\"-1\">Joy and Grief<a class=\"c-anchor-link\" href=\"#joy-and-grief\" aria-label=\"permalink\" aria-describedby=\"joy-and-grief\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>After a lengthy process, my wife and I were delighted to adopt a sweet little chocolate, toy-obsessed bulldog named Kodiak.</p>\n<p>It was a bit stressful for the first couple of weeks, but around week three Kodi started to feel like family.</p>\n<p>He loved being cradled like a baby and snuggled. He would often lay on his back next to my wife in our recliner, and he would always let us know when he thought we weren’t giving him enough attention with his adorable grunts of discontent.</p>\n<p>He filled our home with laughter.</p>\n<p>A few weeks after adopting Kodi, on what we thought was a routine teeth cleaning at the vet, we learned that he had an aggressive, terminal illness.</p>\n<p>We were devastated.</p>\n<p>The vet said he had maybe a week left. Kodi held on for two.</p>\n<p>We tried to fit as much as we could into his last days. We celebrated his birthday, we celebrated Christmas in June, and we made sure he was always surrounded by his favorite toys.</p>\n<p>The end came all too soon, after his final check up at the vet.</p>\n<p>We made sure he was comfortable, then, with tears in our eyes, we held him one last time as he went to sleep on his bed.</p>\n<p>We didn’t want to let go.</p>\n<p>We only knew Kodi for two months, but in that short time, he made an enormous impact on our family.</p>\n<p>We miss him dearly, and will never forget the joy and laughter he gave us. He was such a sweet boy, and we’re glad we were able to give him the best life we possibly could in his final days.</p>\n<p>Meanwhile, a much more welcome changes were happening at work.</p>\n<h2 id=\"a-new-role\" tabindex=\"-1\">A New Role<a class=\"c-anchor-link\" href=\"#a-new-role\" aria-label=\"permalink\" aria-describedby=\"a-new-role\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Earlier this year I moved into a new role as a Yum! Staff Engineer.</p>\n<p>My primary focus is frontend architecture, which means a lot more drawing diagrams and writing documentation. I’m also continuing my work to improve frontend developer experience, something I’ve become quite passionate about.</p>\n<p>My work this year has been all about transitioning a monolithic React application to micro frontends. We’ve been building up to this for a while now by splitting up the existing legacy code into several domain-based vertical slices.</p>\n<p>Now, with the help of module federation, we’re stitching those slices together inside a shell application.</p>\n<p>The micro frontend implementation was completed earlier this year, and now we’re working on the infrastructure bit. It’s exciting, and a bit stressful, to be building something our company has never built before.</p>\n<p>We’ll probably spend the next couple months working out the bugs, but we’re almost to the finish line!</p>\n<h2 id=\"2025-wrapped\" tabindex=\"-1\">2025 Wrapped<a class=\"c-anchor-link\" href=\"#2025-wrapped\" aria-label=\"permalink\" aria-describedby=\"2025-wrapped\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>To round out my personal updates, here’s a quick look at what else happened throughout the year.</p>\n<ul>\n<li>In 2024, I said I wanted to develop a writing habit. Thanks to my new role at work, <strong>I’m writing documentation almost every week.</strong> Now I just need that to translate that to this blog.</li>\n<li>This year we started an AI pilot program at work, and <strong>I’ve begun working with Cursor for the last few months.</strong> It’s been extremely helpful in certain respects, but working with a large legacy codebase presents some unique challenges. The wide variety of patterns and components, most of which we consider deprecated, tend to pollute the context. Next year I plan on devoting a big chunk of my time to improving the overall agent experience.</li>\n<li><strong>In 2025 I read 15 books.</strong> That’s half the number I wanted to tackle, but a lot of those books were massive. This year I tackled the entirety of Brandon Sanderson’s Stormlight Archive series, as well as every other Cosmere related book I could get my hands on. I especially loved <em>Yumi and the Nightmare Painter</em>, one of Sanderson’s secret project books.</li>\n<li>Even though I didn’t get a chance to present in person this year, <strong>I delivered a handful of presentations this year in my team’s bi-weekly Tech Discussions.</strong> The majority of them this year centered around changes to our frontend tech stack.</li>\n<li><strong>My wife and I traveled to Vermont in late October</strong> for some much needed rest. Highlights include apple picking in a picturesque orchard surrounded by mountains, visiting the insanely popular Vermont Country Store, and eating at a restaurant on top of a glass studio and beside a waterfall. Vermont was absolutely gorgeous, and their commitment to farm to table is next level.</li>\n<li>In addition to continuing my regular exercise habit, <strong>I’ve begun daily mindfulness meditation.</strong> I am an eternal skeptic, but I am noticing improvements in my mindfulness, especially around reacting to what have traditionally been triggers for me. I’m going to try to stick with it throughout the next year and see if I notice any further changes.</li>\n<li>I began illustrating again. Specifically, **I illustrated a new drawing daily for an entire month. **Illustration was the first creative hobby I fell in love with. I often dreamed about becoming an artist when I was a kid, and it’s the main reason I got into graphic design. I really haven’t drawn since becoming a software engineer, and this creative exercise was both energizing and healing.</li>\n<li>Finally, <strong>I have begun the process of a long-overdue website renovation.</strong> Coming in 2026. Probably.</li>\n</ul>\n<h2 id=\"2026-goals\" tabindex=\"-1\">2026 Goals<a class=\"c-anchor-link\" href=\"#2026-goals\" aria-label=\"permalink\" aria-describedby=\"2026-goals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In 2026, I want to focus personally on continuing what’s working and experimenting with creating new creative habits. Professionally, I am looking at one of my most ambitious years ever.</p>\n<ul>\n<li>\n<p><strong>Complete and support micro frontend delivery.</strong></p>\n<p>We have a presentation scheduled in February to signify the roll out of our micro frontend workflow, and we have several teams already in line to try it out. I anticipate a big portion of my time in 2026 will be devoted to supporting these projects. At the same time, I will be delivering and editing documentation, as well as establishing governance guidelines to help teams that are unfamiliar with frontend practices.</p>\n</li>\n<li>\n<p><strong>Frontend democratization project.</strong></p>\n<p>The documentation and governance work for the micro frontend architecture will be the first step in creating a complete org-wide frontend system. I envision a future where teams can spin up new frontend integrations with the push of a button, with accessible and flexible components, utilities that make interfacing with custom backends a breeze, and scaffolding tools that integrate seamlessly with AI agents to supercharge</p>\n</li>\n<li>\n<p><strong>Deliver a talk at our React meetup.</strong></p>\n<p>This year I am going to make giving an in-person talk a priority. I am working on a presentation right now, and I hope to be able to get on the schedule for a React meetup that takes place at our Plano office. Either way, I plan on posting a written version of this talk as well.</p>\n</li>\n<li>\n<p><strong>Commit to creativity experiment aimed at developing creative habit for 90 days.</strong></p>\n<p>I’m attempting to create one new thing a day for the first 90 days of 2026, whether it’s an illustration, a guitar riff, or some UI interaction that’s rolling around in my head. I’ll start with two to three days a week, 30–45 mins per session. Then each week I’ll reflect on what I did (or did not do). I want to develop a sense of creative identity without any kind of self-imposed pressure, so I’m trying to keep the structure loose and informal. I’m hoping this will turn into something interesting.</p>\n</li>\n<li>\n<p><strong>Read 16 books.</strong></p>\n<p>I think the important thing here is that I want to continue my reading habit. I’m really enjoying the fantasy and sci-fi genre, and I’ve really gotten into Brandon Sanderson. Now that I’ve read literally everything he’s ever written, I need to branch out and see what I can find.</p>\n</li>\n<li>\n<p><strong>Meditate and exercise daily.</strong></p>\n<p>Finally, I want to continue my meditation habit, 20 minutes a day. For exercise, I want to continue weight lifting and walking. This has been a combination that really works for me, and I’ve grown to enjoy my exercise time.</p>\n</li>\n</ul>\n<p>Something I’m doing different this year is setting a calendar reminder to review all of my goals monthly. Hopefully this will keep me focused on what my priorities are, and, if anything changes, I can easily update my goals and note the reason for the change.</p>\n<h2 id=\"signing-off-for-now\" tabindex=\"-1\">Signing Off for Now<a class=\"c-anchor-link\" href=\"#signing-off-for-now\" aria-label=\"permalink\" aria-describedby=\"signing-off-for-now\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>2025 was exhausting for me on many levels, but I’m proud of the work I accomplished and thankful for my family, especially my wife, for their love and support. I’m also grateful that I was able to meet the sweetest dog I’ve ever known, even if it was for such a brief time.</p>\n<p>I’m taking the last two weeks of this year to rest, reflect and regroup. I hope you are able to do the same. Until next time!</p>\n",
      "date_published": "2025-12-26T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/year-end-review-2024/",
      "url": "https://www.falldowngoboone.com/blog/year-end-review-2024/",
      "title": "Year-end review 2024",
      "content_html": "<p><strong>2024 is wrapping up, and it’s time for me to post my annual year-end review.</strong> This year brought its share of challenges and uncertainties globally. Personally, though, I am grateful for what I was able to experience and accomplish.</p>\n<h2 id=\"2024-goals\" tabindex=\"-1\">2024 Goals<a class=\"c-anchor-link\" href=\"#2024-goals\" aria-label=\"permalink\" aria-describedby=\"2024-goals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Spoiler alert: <strong>three out of five were completed successfully.</strong> I swear I’ll review these throughout the year <em>one day</em>. Honestly, I think the biggest barrier to accomplishing the goals I set is actually <em>remembering</em> them. As always, I continue to struggle with writing my blog, but I have a plan for that.</p>\n<ul>\n<li>\n<p>❌ <strong>Publish three articles to my Dev Community account.</strong></p>\n<p>I thought that setting a much lower goal would help me have a more productive year, but no such luck. I managed to publish once or twice, but never to my Dev Community account.</p>\n<p>This was not for lack of trying. I started multiple articles, but I’ve found that unless I complete them quickly, I lose interest. I hope to change that in 2025, and I’ll detail that a bit more later on in my 2025 goals.</p>\n</li>\n<li>\n<p>✅ <strong>Give three presentations.</strong></p>\n<p>Since I lead a bi-weekly tech discussion with my dev team, this goal was probably the easiest to accomplish. This year, I shared talks on continuous integration techniques, QA process improvements, and a deep dive into my current work rearchitecting our front-end application.</p>\n</li>\n<li>\n<p>✅ <strong>Read at least 24 books.</strong></p>\n<p>This goal was fairly difficult this year in particular because I started reading the <em>Stormlight Archive</em> series by Brandon Sanderson, and those books are massive. I barely squeaked by but was able to also fit in some great non-fiction books focused on software architecture and process.</p>\n</li>\n<li>\n<p>❌ <strong>Take the Primeagen algorithms course on Frontend Masters.</strong></p>\n<p>The time I’ve traditionally used for learning was taken up by a massive project for most of the year (more on that below), so I didn’t get much FEM time in this year. However, I did restart my subscription and managed to knock out a few courses before the end of the year. To be honest, I completely forgot I had set this as a goal last year.</p>\n</li>\n<li>\n<p>✅ <strong>Travel to two places I’ve never been before.</strong></p>\n<p>When I made this goal, I already knew my wife and I were heading to Asheville, North Carolina, at the beginning of the year. We stayed at a wonderful inn, toured the Biltmore Estate, explored the Blue Ridge Mountains, and enjoyed the downtown area. It was heartbreaking to see the devastation caused by Helene in September, and our thoughts are with those who were directly affected.</p>\n<p>The second trip was one my wife and I had talked about doing for years. More on that in the year’s highlights.</p>\n</li>\n</ul>\n<p>One thing that continues to roll around in the back of my head is the idea of recording music again. I didn’t make it a goal this year because I knew I wouldn’t have (or make) time for it. I remain hopeful I’ll return to making music but accept that it’s not a priority in my life right now.</p>\n<h2 id=\"additional-highlights\" tabindex=\"-1\">Additional highlights<a class=\"c-anchor-link\" href=\"#additional-highlights\" aria-label=\"permalink\" aria-describedby=\"additional-highlights\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In addition to my personal goals, 2024 presented me with some unique opportunities, as well as things I just want to celebrate.</p>\n<p>Starting with the most recent event: <strong>My wife recently underwent what we hope will be her last major cancer-related surgery</strong>. I know she’s exhausted at this point, but she has met every challenge on this journey head-on. I’m so proud of her and grateful to have her in my life.</p>\n<p>Last month, I completed a massive project I began planning in late 2023: <strong>I produced and presented an 8-week course on React.</strong> The course was a project for work, intended to attract more interest in React development. It was well-received, and I’m excited to share what I learned from the experience.</p>\n<p>I continued to work on my personal health as well. <strong>I’ve been lifting weights regularly and hit a personal goal of 13% body fat.</strong> I’m quite happy with that, especially considering I started the year off with physical therapy due to back and neck pain.</p>\n<p>Finally, I mentioned that my wife and I made two trips this year, and the second trip had been years in the making. <strong>This year, we finally made our way across the pond to the United Kingdom.</strong> We spent a week and a half exploring London, Canterbury, Edinburgh, and Glasgow by train. It was definitely the high point of the year, and we can’t wait to go back.</p>\n<h2 id=\"2025-goals\" tabindex=\"-1\">2025 Goals<a class=\"c-anchor-link\" href=\"#2025-goals\" aria-label=\"permalink\" aria-describedby=\"2025-goals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>For 2025, I want to focus on creating systems around what I want to accomplish, using the principles of <em>Atomic Habits</em> by James Clear. And for fun, I’m using ChatGPT to generate possible strategies for each goal.</p>\n<ul>\n<li><strong>Develop a writing habit.</strong> I want to start a daily writing goal, and hopefully it’ll translate to more content here and elsewhere. I’m aiming for ten minutes a day, and I will track progress in a habit tracking app.</li>\n<li><strong>Average three hours a week on Frontend Masters.</strong> Now that I’ve renewed my Frontend Masters membership, I have a lot to catch up on. I already have a massive list of courses bookmarked, so I’ll need to be intentional with what I want to learn.</li>\n<li><strong>Read 30 books.</strong> This feels a bit ambitious considering I barely read 24 books this year, but I know I can do it. Again, I want to have a good mix of fiction and non-fiction. For non-fiction, I want to focus on personal growth.</li>\n<li><strong>Give at least one presentation in front of a live audience.</strong> So far, most of my presentations and talks have been on conference calls. I’d like to get out in front of an audience again. I’ve had an offer from a local meetup, I just need to come up with a topic.</li>\n<li><strong>Revamp my website.</strong> It’s been a few years since I launched this version of my blog. It’s actually the furthest I’ve ever gone with building my own website out, and I’ve been very happy with it. However, recently I’ve been feeling the itch to take it even further by adding a few bells and whistles, as well as creating new visuals. This particular goal may be the hardest one I set, considering my track record with personal projects, so completing it would be a huge accomplishment.</li>\n</ul>\n<h2 id=\"see-you-in-the-new-year\" tabindex=\"-1\">See you in the New Year<a class=\"c-anchor-link\" href=\"#see-you-in-the-new-year\" aria-label=\"permalink\" aria-describedby=\"see-you-in-the-new-year\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So that was my 2024: a UK trip, a React course, and my wife one more year cancer-free. It was one of the best years I’ve had in a while. Even though there’s a lot of uncertainty about what’s happening in the world, I’m looking forward to 2025. This year, I aim to focus more on the present, and I hope others find the balance that works for them.</p>\n<p>Until next time (hopefully not too long from now)!</p>\n",
      "date_published": "2024-12-29T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/cracking-the-books/",
      "url": "https://www.falldowngoboone.com/blog/cracking-the-books/",
      "title": "Cracking the books",
      "content_html": "<p>If you’re like me, you’re 6’2”, have terrible eyesight, and a weird affinity for <a href=\"https://www.youtube.com/@twoodfrd\">guitar repair videos</a>. You probably also like to read.</p>\n<p>One of my <a href=\"https://www.falldowngoboone.com/blog/year-end-review-2023/#2024-goals\">goals this year</a> is to read at least 24 books, and I’m off to a pretty good start. While I’m trying to work more fiction into my reading, I still love a good software engineering book.</p>\n<p>So you can imagine how excited I was to come across this <a href=\"https://youtu.be/Y2iJOPxw0JU?si=KrRy0d7yVg86HGx5\">gem of a video</a> from Engineering with Utsav. Utsav has put together a small but mighty collection of software engineering books that would make any nerd happy.</p>\n<p>I’ve added all of these books to my Notion bookshelf, and I’m looking forward to checking them out!</p>\n<p>Video: <a href=\"https://youtu.be/Y2iJOPxw0JU?si=KrRy0d7yVg86HGx5\">Books every software engineer should read in 2024</a> (Youtube)</p>\n",
      "date_published": "2024-03-09T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/year-end-review-2023/",
      "url": "https://www.falldowngoboone.com/blog/year-end-review-2023/",
      "title": "Year-end review 2023",
      "content_html": "<p>The last three years have been…interesting, but I finally feel like my life is getting back to some sense of normal. 2023 was my first full year as a tech lead, and I have noticed a definite change in my day-to-day activities. My wife and I also celebrated an important milestone that I’m grateful to share. With that in mind, here’s the obligatory look back on my year, as well as a look forward to what I want to accomplish in 2024.</p>\n<h2 id=\"2023-goals\" tabindex=\"-1\">2023 Goals<a class=\"c-anchor-link\" href=\"#2023-goals\" aria-label=\"permalink\" aria-describedby=\"2023-goals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>First, let’s tackle by 2023 goals from last year. I feel like I fared rather well, all things considered.</p>\n<ul>\n<li>\n<p>❌ <strong>Mess around with music more this year.</strong></p>\n<p>Yeesh. This was the one goal I pretty much did not accomplish. I don’t even think I picked up my guitar once this past year. I purchased a music theory course early on, but faltered a couple weeks in.</p>\n<p>I guess I’m not surprised. Most of my spare time is devoted to coding or reading. I think one of the biggest challenges here is I don’t really have a good set up for playing/writing music. My work computer is always hooked up in the office, and I have to rearrange a bunch of stuff (and update software) just to record anything.</p>\n</li>\n<li>\n<p>✅ <strong>More reading for pleasure.</strong></p>\n<p>I read 30 books this year, which is probably more than I’ve read in the past ten years combined. I rediscovered my love of fantasy with <em>The Wheel of Time</em> and read my first Stephen King novels with the <em>Dark Tower</em> series.</p>\n<p>I think a big contributing factor to reading so many books this year was the heavy emphasis on series. It’s easy for me to read a lot when I <em>know</em> what I’m reading next. It’ll be interesting to see how many I can read in the coming year.</p>\n</li>\n<li>\n<p>😐 <strong>Revisit some of my favorite books on software engineering.</strong></p>\n<p>While I did revisit concepts in some of my favorite books, I did not get around to writing about them. I didn’t do any writing at all! What I did do was share those books with my team members.</p>\n<p>One book that continually came up in conversation was John Ousterhout’s <em>A Philosophy of Software Design</em>. It reads like a novel and offers some compelling thoughts on software design, something that’s, surprisingly, not well-taught. If you haven’t read this book and you are a software developer, I highly recommend it.</p>\n</li>\n<li>\n<p>✅ <strong>Get back to lifting two or three times a week.</strong></p>\n<p>This year was my most active in a long time. I’ve continually walked on my treadmill, and, most recently, I’ve begun working out with the X3 Bar. It’s somewhat controversial (or, rather, I guess it’s inventor is), but it’s really helped me get back into lifting.</p>\n<p>If you don’t know what the X3 Bar is, it’s basically latex bands that hook onto a bar that’s meant to mimic barbell lifts. The bands offer variable resistance, which its inventor claims is superior to working out with traditional weights. I don’t know whether or not that’s true, but it’s a compact system that gives me more than enough resistance for the time being. I’ll hopefully have more to talk about in the next year-end review.</p>\n</li>\n<li>\n<p>✅ <strong>Rearchitect the front-end project I work on.</strong></p>\n<p>Without getting too much into detail, we’ve begun several projects that are slowly rearchitecting our project. We are slowly breaking our application up into several applications that will all live in a monorepo. I’ve been learning a ton about Nx, particularly how to use it to manage dependencies and enforce module boundaries.</p>\n<p>I’m really excited about Nx and the potential it has to streamline our development process. There are some intriguing features they have planned in the near future, and I can’t wait to really dig in.</p>\n</li>\n<li>\n<p>✅ <strong>Build a form system.</strong></p>\n<p>After about a year of messing around with the API design, I’m finally shipping production code that uses our new form system. It’s heavily inspired by Formik, but with a true fast field array strategy inspired by React Hook Form. The system was built in layers: a state layer managed by Zustand, an adapter layer that uses custom hooks, and a component layer. This should (hopefully) make each layer easily replaceable in the future.</p>\n<p>I’ve now shifted my focus replacing the multi-step form component we currently use with a new design that leverages this new form system. I really enjoy this type of work because of all the challenges involved, particularly with the API design. This component needs to handle extreme customization and still be easy to use for the majority of use cases.</p>\n</li>\n<li>\n<p>😐 <strong>Finish my talk and/or article on component architecture.</strong></p>\n<p>Let me start by saying there <em>is</em> an article. In fact, there are seven. I’ve just not felt good about the content, mainly because I’ve never been sure of the interest and whether or not I have anything new to bring to the table regarding this topic.</p>\n<p>Another reason I’ve not put out anything on this topic is I’ve needed time to organize my thoughts. Those seven articles all say a lot of the same things but in different ways. I’m still trying to find the best way to communicate my ideas and opinions in a way that’s organized and very much from my own experience. Having said that, I think one of my goals this next year will be to finally publish this latest incarnation of the article, so look forward to that.</p>\n</li>\n</ul>\n<h2 id=\"the-highlight-of-my-year\" tabindex=\"-1\">The highlight of my year<a class=\"c-anchor-link\" href=\"#the-highlight-of-my-year\" aria-label=\"permalink\" aria-describedby=\"the-highlight-of-my-year\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you read <a href=\"https://www.falldowngoboone.com/blog/year-end-review-2022/\">my year-end review for 2022</a>, you’ll know my wife was diagnosed with breast cancer in September of that year. She underwent an experimental treatment in December 2022, then surgery in November of this year.</p>\n<p>It’s been a long, scary, sometimes extremely stressful road, but I am more than pleased to report she has been classified cancer free! After the experimental treatment, her tumor has completely disappeared, and there was no sign of microscopic cancer cells in her lymph nodes. This has been a huge relief to us both, and we’re taking some time to celebrate.</p>\n<h2 id=\"2024-goals\" tabindex=\"-1\">2024 Goals<a class=\"c-anchor-link\" href=\"#2024-goals\" aria-label=\"permalink\" aria-describedby=\"2024-goals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li><strong>Publish three articles to my <a href=\"https://dev.to/falldowngoboone\">Dev Community account</a>.</strong> I would like to do this once a month, three months in a row. I already have some ideas, including the component architecture article mentioned earlier.</li>\n<li><strong>Give three presentations.</strong> My team hosts a discussion hour every other week, and I try to contribute regularly to it. Some of those presentations can even end up being article ideas, and even talk ideas for meet ups, conferences, etc.</li>\n<li><strong>Read at least 24 books.</strong> I intend to keep my reading pace up. I’m always open to reading suggestions, so please send some my way if you have any.</li>\n<li><strong>Take the <a href=\"https://frontendmasters.com/courses/algorithms/\">Primeagen algorithms course on Frontend Masters</a>.</strong> This is the year I gain better knowledge of algorithms. The problems that we solve in our front end architecture scale to massive size with some of our brands, so more and more we are relying on algorithms to help solve these scaling challenges.</li>\n<li><strong>Travel to two places I’ve never been before.</strong> If there’s one thing my wife and I have learned from the past three years, it’s that the time to create experiences is now. We’re checking out Asheville, NC, first, but I’d like to see Chicago, Vancouver, and Montreal (maybe Quebec City for Christmas 2024?) as well. We’re putting some ideas together for a European trip in 2025, and I’d love to see Japan as well.</li>\n</ul>\n<h2 id=\"see-you-in-the-new-year\" tabindex=\"-1\">See you in the New Year<a class=\"c-anchor-link\" href=\"#see-you-in-the-new-year\" aria-label=\"permalink\" aria-describedby=\"see-you-in-the-new-year\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>That’s all I have for now. I hope you had a great year and I hope your 2024 is even better. You’ll hopefully see more of me in the near future now that I finally feel like I have my bearings. Until next time!</p>\n",
      "date_published": "2024-01-01T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/year-end-review-2022/",
      "url": "https://www.falldowngoboone.com/blog/year-end-review-2022/",
      "title": "Year-end review 2022",
      "content_html": "<p>What. Just. Happened?</p>\n<p>And I thought <a href=\"https://www.falldowngoboone.com/blog/year-end-review-2021/\">2021</a> was crazy.</p>\n<p>2022 was a roller coaster of emotion for many people. We saw historical weather events, political events, everything. I would like to, for once, have a year that is not historic.</p>\n<p>My year was wild, filled with terrific ups and terrifying downs. What follows is a quick overview of my 2022.</p>\n<h2 id=\"2022-opportunities-reviewed\" tabindex=\"-1\">2022 opportunities reviewed<a class=\"c-anchor-link\" href=\"#2022-opportunities-reviewed\" aria-label=\"permalink\" aria-describedby=\"2022-opportunities-reviewed\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li><strong>Publish 42 articles in 2022.</strong> For someone with a track record of not blogging regularly, 42 articles was a lofty goal. One of the things I was counting on was publishing an article every day in the month of February. That didn’t happen, though, mainly because my responsibilities at work increased. It’s tough to write an entire article after a nine-hour workday, and I didn’t really account for that.</li>\n<li><strong>Finish up all current issues in my projects list.</strong> I still have nine issues to tackle, but <a href=\"https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-1-the-notion-api/\">I managed to integrate Notion into my blog workflow</a>, which was probably the biggest issue in my backlog.</li>\n<li><strong>Build 3 projects from my project backlog.</strong> My project backlog remains untouched, but I think I’ve more than made up for it with my list of projects at work.</li>\n<li><strong>Work out at least twice a week, and go on at least one 40-minute walk a week.</strong> One of our Christmas presents to ourselves was a treadmill. Since assembling it (which was quite a workout all its own), I walk at least 40 minutes a day, and I love it.</li>\n<li><strong>Move to a new state.</strong> Sadly, this one did not happen and won’t for a while. More on that later.</li>\n</ul>\n<h2 id=\"other-2022-accomplishments\" tabindex=\"-1\">Other 2022 accomplishments<a class=\"c-anchor-link\" href=\"#other-2022-accomplishments\" aria-label=\"permalink\" aria-describedby=\"other-2022-accomplishments\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>First, I guess the biggest news is <strong>I was promoted to project tech lead!</strong> I plan on writing more about this in the near future, but my new responsibilities include guiding the technological direction of our project and representing our project’s code to the rest of the company.</li>\n<li><strong>A major phase of the project I work on, which had been in development for over a year and a half, finally went live this year.</strong> This was as exciting as it was scary. We have identified a few issues, but overall the launch went smoothly.</li>\n<li>2022 was the year <strong>I returned to reading fiction.</strong> I blew through <em>The Dark Tower</em> series (Stephen King) and have started the <em>Book of Swords</em> (Fred Saberhagen) epic. It’s been a breath of fresh air since most of what I read is tech-focused nonfiction.</li>\n<li><strong>I also picked up art again.</strong> I’ve been playing around with Procreate on my iPad Pro. I love the Apple Pencil, and Procreate is a fantastic medium for anything from casual sketching to painting digital works of art.</li>\n<li>I can barely believe it, but this year <strong>I celebrated 20 years with my wonderful wife.</strong> We married just out of college and dated for seven years prior. She has been my best friend through the best and worst times of my life, and I would not be where I am without her. I am looking forward to another 20!</li>\n</ul>\n<h2 id=\"2022-challenges\" tabindex=\"-1\">2022 challenges<a class=\"c-anchor-link\" href=\"#2022-challenges\" aria-label=\"permalink\" aria-describedby=\"2022-challenges\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>Twitter has been the only social media platform I’ve participated in for years, and recent events have me questioning whether or not I should continue. For the time being, I’ve adopted a wait-and-see approach. But, you never know, <strong>you might see me on TikTok in 2023.</strong></li>\n<li>For almost the past decade, my only hobby has been programming. After my recent promotion, though, I began longing for old hobbies. I mentioned earlier that I returned to reading fiction and began creating digital art.** I’ve also wanted to return to writing and performing music, but my schedule has made that difficult.**</li>\n<li>Probably the ultimate challenge I faced in 2022 was one of the scariest things I’ve ever experienced. In September, <strong>my wife was diagnosed with breast cancer.</strong> Thankfully the cancer was discovered early on, but it changed the course of our lives for the next few years as my wife goes through treatment.</li>\n<li>Because of the nature of my wife’s treatment, <strong>we’ve been forced to postpone our plans to move.</strong> This was a huge disappointment to both of us, but I care much more for my wife’s health than a change of scenery.</li>\n</ul>\n<h2 id=\"2023-goals\" tabindex=\"-1\">2023 goals<a class=\"c-anchor-link\" href=\"#2023-goals\" aria-label=\"permalink\" aria-describedby=\"2023-goals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li><strong>I would love to mess around with music more this year.</strong> I’m toying with the idea of taking a music vacation where I work on writing for a whole week. Regardless, I need to <em>make</em> time for the things I want to do.</li>\n<li><strong>More reading for pleasure.</strong> I want to complete the <em>Book of Swords</em> epic this year (which, from what I understand, is HUGE). I would love to make my bookshelf public as well.</li>\n<li>Related to the last goal, <strong>I want to revisit some of my favorite books on software engineering</strong> and talk about what I love about them in more detail. Sort of like a series of book reports.</li>\n<li>I want to continue my workout streak and get back to lifting two or three times a week.</li>\n<li>One huge work goal is to <strong>rearchitect our front-end project.</strong> We need to scale up outside contributions as well as speed up feature development, so we’re betting big on splitting up our project into specific solutions.</li>\n<li><strong>I also want to replace our project’s form system,</strong> which probably accounts for 85% of the project. Our current system was not built to handle the complex forms we have been building as of late, and it’s negatively affecting our velocity. I’ve already started this work and I’d love to see it finished in the first half of 2023.</li>\n<li>I didn’t get to do any conference talks in 2022, but I’m already planning <strong>a talk around component architecture.</strong> At the very least, this work will end up as a series of articles here, so be on the lookout for that.</li>\n</ul>\n<h2 id=\"till-next-year\" tabindex=\"-1\">Till next year<a class=\"c-anchor-link\" href=\"#till-next-year\" aria-label=\"permalink\" aria-describedby=\"till-next-year\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Well, I’m done for 2022. It’s been real, and it’s been fun, but I’m ready for a boring year. Seriously.</p>\n<p>What are you excited about in 2023? <a href=\"https://twitter.com/therealboone\">Let me know on Twitter</a> (assuming it continues to work), and I’ll see you again next year!</p>\n",
      "date_published": "2022-12-28T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-2-building-markdown-from-json/",
      "url": "https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-2-building-markdown-from-json/",
      "title": "From Notion to Eleventy part 2: Building Markdown from JSON",
      "content_html": "<p>This is the second article in an ongoing series where I explore using Notion’s API to directly build a blog post for Eleventy. In <a href=\"https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-1-the-notion-api/\">the first post of this series</a>, I used the Notion API to write a local JSON file representing all the data that I need to stitch together a blog post. In this blog post, I’m going to turn that ball of JSON into a Markdown file.</p>\n<aside class=\"c-post__aside c-post__aside--info\"><p>This post focuses more on the <em>why</em> and <em>how</em> of my current solution. If you’re just interested in the code, you can <a href=\"https://github.com/falldowngoboone/falldowngoboone-com/tree/main/scripts/publish-page\">check that out on GitHub</a>.</p>\n</aside>\n<p>You might ask, <em>Ryan, doesn’t Notion already have a Markdown export feature?</em> Yes, Notion <em>does</em> have a Markdown export feature, but there are a couple reasons why I want something more custom.</p>\n<p>First, every time I export an article, the first thing I have to do (aside from unpacking the <code>zip</code> package, renaming the file, and moving it to the appropriate directory) is format the front matter. This work is trivial but tedious, and surprisingly open to error.</p>\n<pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">title</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"This is an example of my front matter\"</span><br><span class=\"token key atrule\">date</span><span class=\"token punctuation\">:</span> <span class=\"token datetime number\">2022-02-22</span><br><span class=\"token key atrule\">excerpt</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Sometimes I include an excerpt here.\"</span><br><span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span><br>  <span class=\"token punctuation\">-</span> example<br>  <span class=\"token punctuation\">-</span> front matter</code></pre>\n<p>Second, I would like more control over how to interpret the content I get from Notion. For example, Notion exports callout blocks as <code>&lt;aside&gt;</code>s with emoji icons. I would like to write those callout blocks as custom Eleventy <a href=\"https://www.11ty.dev/docs/shortcodes/#paired-shortcodes\">paired shortcodes</a> or even React components.</p>\n<pre class=\"language-markdown\"><code class=\"language-markdown\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>aside</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-post__aside c-post__aside--info<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>This is an example of my <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>code</span><span class=\"token punctuation\">></span></span>aside<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>code</span><span class=\"token punctuation\">></span></span> shortcode. It renders as an <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>code</span><span class=\"token punctuation\">></span></span>aside<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>code</span><span class=\"token punctuation\">></span></span><br>with a special class.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>aside</span><span class=\"token punctuation\">></span></span></code></pre>\n<h2 id=\"the-plan\" tabindex=\"-1\">The plan<a class=\"c-anchor-link\" href=\"#the-plan\" aria-label=\"permalink\" aria-describedby=\"the-plan\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I’ve never written a Markdown formatter before, but I know I need to start with breaking the problem down into manageable steps. The plan will most likely change throughout the process as I surface unknown or unanticipated challenges, but it serves as a good starting place. After a little bit of thought, my plan is as follows:</p>\n<ol>\n<li>\n<p><strong>Combine page properties and the main content into a single JSON structure.</strong> To write the entire file, I’ll <em>at least</em> need the page properties and child blocks. I can combine both pieces into a single object like this:</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">\"frontMatter\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* page properties */</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>  <span class=\"token property\">\"content\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* child blocks */</span><span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n</li>\n<li>\n<p><strong>Format the front matter.</strong> On my blog, <a href=\"https://www.11ty.dev/docs/data-frontmatter/\">front matter</a> is formatted in YAML, which is whitespace sensitive. I think I can utilize a simple template literal to properly format this, but I may need something to format rich text objects, which is a trickier problem than it may initially seem.</p>\n</li>\n<li>\n<p><strong>Format the content.</strong> My blog posts are formatted in Markdown which, like YAML, is whitespace sensitive. Unlike the front matter, though, I can’t use template literals due to the dynamic nesting of child blocks. I’ll need to figure out how to properly write line padding and line returns to the page. And just like the previous step, I’ll need a solution for formatting rich text objects.</p>\n</li>\n<li>\n<p><strong>Create the file structure for the post and write the file.</strong> This is work I’m very familiar with, at least at a level that’s needed for the initial solution.</p>\n</li>\n</ol>\n<aside class=\"c-post__aside c-post__aside--info\"><p>I recently broke down <a href=\"https://www.falldowngoboone.com/blog/how-i-solve-complex-problems/\">my personal framework for solving complex problems</a>, just in case you’re interested.</p>\n</aside>\n<p>I will start with step three, formatting the content, which I believe demands the most effort. I already have code that fetches page properties and content, so step one seems like it’s simply writing a third function that combines the first two calls. Step four, as I’ve noted, is something I’ve done multiple times in the past. And I’m guessing that if I can solve step three, I’ll be in a much better position to finish step two quite easily.</p>\n<h2 id=\"let%E2%80%99s-print-a-page\" tabindex=\"-1\">Let’s print a page<a class=\"c-anchor-link\" href=\"#let%E2%80%99s-print-a-page\" aria-label=\"permalink\" aria-describedby=\"let%E2%80%99s-print-a-page\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>My approach to writing the page content is to imagine I’m writing the page myself in a text editor. When writing Markdown, I start a new line, indent, write my content, rinse and repeat. This metaphor will help me define methods and variable names.</p>\n<p>I’ll also need a way to format content before I write it to the page. When I’m writing Markdown, I <em>just know</em> that two hashes and a space before content (<code>## Content</code>) denotes a second-level heading. Since each <a href=\"https://developers.notion.com/reference/block\">block object</a> in the Notion API has a type and configuration specific to that type, I can build methods for each block type that <em>just know</em> how to format that type with the given configuration.</p>\n<p>With this context in mind, this is what I came up with:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Printer</span> <span class=\"token punctuation\">{</span><br>  #writers<span class=\"token punctuation\">;</span><br>  #opts<span class=\"token punctuation\">;</span><br>  #indentLevel <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span><br>  #page <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">writers<span class=\"token punctuation\">,</span> opts</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers <span class=\"token operator\">=</span> writers<span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#opts <span class=\"token operator\">=</span> opts<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">#writeProperties</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">properties</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> frontMatter <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#opts<span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeLine</span><span class=\"token punctuation\">(</span><span class=\"token function\">frontMatter</span><span class=\"token punctuation\">(</span>properties<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">#writeContent</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block<span class=\"token punctuation\">,</span> parent <span class=\"token operator\">=</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> index <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> blocks <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">child<span class=\"token punctuation\">,</span> i</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span><br>        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeContent</span><span class=\"token punctuation\">(</span>child<span class=\"token punctuation\">,</span> parent<span class=\"token punctuation\">,</span> i<span class=\"token punctuation\">,</span> block<span class=\"token punctuation\">)</span><br>      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br><br>    <span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>block<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>    writer<span class=\"token operator\">?.</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      block<span class=\"token punctuation\">,</span><br>      parent<span class=\"token punctuation\">,</span><br>      index<span class=\"token punctuation\">,</span><br>      blocks<span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">writeLine</span><span class=\"token operator\">:</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeLine</span><span class=\"token punctuation\">.</span><span class=\"token function\">bind</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br><br>      <span class=\"token comment\">// convenience fields</span><br>      <span class=\"token literal-property property\">isFirst</span><span class=\"token operator\">:</span> index <span class=\"token operator\">===</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">isLast</span><span class=\"token operator\">:</span> index <span class=\"token operator\">===</span> blocks<span class=\"token punctuation\">.</span>length <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">prev</span><span class=\"token operator\">:</span> blocks<span class=\"token punctuation\">[</span>index <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">next</span><span class=\"token operator\">:</span> blocks<span class=\"token punctuation\">[</span>index <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span><br>      <span class=\"token function\">getConfig</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> type<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> config <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>        <span class=\"token keyword\">return</span> config<span class=\"token punctuation\">;</span><br>      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>has_children<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#indent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeContent</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">,</span> block<span class=\"token punctuation\">,</span> index<span class=\"token punctuation\">,</span> blocks<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#dedent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">#writeLine</span><span class=\"token punctuation\">(</span>content <span class=\"token operator\">=</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#page<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">.</span><span class=\"token function\">padStart</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#indentLevel <span class=\"token operator\">*</span> <span class=\"token constant\">SPACES</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#page<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#page<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token constant\">NEW_LINE</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">#indent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#indentLevel<span class=\"token operator\">++</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">#dedent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#indentLevel<span class=\"token operator\">--</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">#printPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#page<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">print</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> frontMatter<span class=\"token punctuation\">,</span> content <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeProperties</span><span class=\"token punctuation\">(</span>frontMatter<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeContent</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#printPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>My writing metaphor’s “page” is represented as a plain array. Pushing content to the array “writes” to the page, then joining the array and returning the result “prints” the page. A single, public method (<code>print</code>) takes our content data structure as an argument, writes it to the page, and returns the results as one continuous string. The <code>writers</code> parameter of the constructor contains the methods that “know” how to format block types.</p>\n<p>Perhaps the most interesting block of code in this class is the <code>#writeContent</code> method:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">#writeContent</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block<span class=\"token punctuation\">,</span> parent <span class=\"token operator\">=</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> index <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> blocks <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">child<span class=\"token punctuation\">,</span> i</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span><br>      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeContent</span><span class=\"token punctuation\">(</span>child<span class=\"token punctuation\">,</span> parent<span class=\"token punctuation\">,</span> i<span class=\"token punctuation\">,</span> block<span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>block<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>  writer<span class=\"token operator\">?.</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>    block<span class=\"token punctuation\">,</span><br>    parent<span class=\"token punctuation\">,</span><br>    index<span class=\"token punctuation\">,</span><br>    blocks<span class=\"token punctuation\">,</span><br>    <span class=\"token literal-property property\">writeLine</span><span class=\"token operator\">:</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeLine</span><span class=\"token punctuation\">.</span><span class=\"token function\">bind</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br><br>    <span class=\"token comment\">// convenience fields</span><br>    <span class=\"token literal-property property\">isFirst</span><span class=\"token operator\">:</span> index <span class=\"token operator\">===</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span><br>    <span class=\"token literal-property property\">isLast</span><span class=\"token operator\">:</span> index <span class=\"token operator\">===</span> blocks<span class=\"token punctuation\">.</span>length <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span><br>    <span class=\"token literal-property property\">prev</span><span class=\"token operator\">:</span> blocks<span class=\"token punctuation\">[</span>index <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span><br>    <span class=\"token literal-property property\">next</span><span class=\"token operator\">:</span> blocks<span class=\"token punctuation\">[</span>index <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span><br>    <span class=\"token function\">getConfig</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> type<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> config <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">return</span> config<span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>has_children<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#indent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#writeContent</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">,</span> block<span class=\"token punctuation\">,</span> index<span class=\"token punctuation\">,</span> blocks<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">#dedent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<aside class=\"c-post__aside c-post__aside--info\"><p>This code, especially the signature for <code>#writeContent</code>, was heavily influenced by Tan Li Hau’s excellent article <a href=\"https://lihautan.com/manipulating-ast-with-javascript/\"><em>Manipulating AST with JavaScript</em></a>. I highly recommend checking it out. In the article, Tan explains how parsing libraries use the Visitor pattern to manipulate nested data structures like our block objects.</p>\n</aside>\n<p>This method recurses through the content blocks, pulls off the correct writer method, and passes in a whole slew of data. This data includes a <code>writeLine</code> method, which writes a single line to the private <code>#page</code> array, including new lines and proper indentation. Here’s a look at what my Markdown writers look like:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> formatters <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token function\">paragraph</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> block<span class=\"token punctuation\">,</span> writeLine<span class=\"token punctuation\">,</span> isLast<span class=\"token punctuation\">,</span> getConfig <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> rich_text <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">getConfig</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token function\">formatRichText</span><span class=\"token punctuation\">(</span>rich_text<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    isLast <span class=\"token operator\">&amp;&amp;</span> <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br><br>  <span class=\"token function\">heading_2</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> block<span class=\"token punctuation\">,</span> writeLine<span class=\"token punctuation\">,</span> isLast<span class=\"token punctuation\">,</span> getConfig <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> rich_text <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">getConfig</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">## </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token function\">formatRichText</span><span class=\"token punctuation\">(</span>rich_text<span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    isLast <span class=\"token operator\">&amp;&amp;</span> <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br><br>  <span class=\"token function\">bulleted_list_item</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> block<span class=\"token punctuation\">,</span> prev<span class=\"token punctuation\">,</span> writeLine<span class=\"token punctuation\">,</span> getConfig <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> rich_text <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">getConfig</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>prev <span class=\"token operator\">&amp;&amp;</span> <span class=\"token operator\">!</span>prev<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">'list_item'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br><br>    <span class=\"token function\">writeLine</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">- </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token function\">formatRichText</span><span class=\"token punctuation\">(</span>rich_text<span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>  <span class=\"token comment\">// ...more</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">formatRichText</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">richTextObjects <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">// more on this later...</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The writer methods have complete control over how they are written based on their siblings. For example, a <code>paragraph</code> type can add an extra line after itself if it is the last block in the array and list items can add an extra line before themselves if they follow a block that is not a list item.</p>\n<p>This architecture allows me the flexibility of changing the output format via different writers while leaving the main compositional logic untouched. The only thing I might later change in the <code>Printer</code> class is making indentation and newlines optional since some formats aren’t whitespace dependent.</p>\n<p>I’m limiting direct interaction with the <code>Printer</code> class by only exporting a function (<code>getPrinter</code>) that instantiates the class:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// in printer.js</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">getPrinter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">writers<span class=\"token punctuation\">,</span> opts <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Printer</span><span class=\"token punctuation\">(</span>writers<span class=\"token punctuation\">,</span> opts<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">export</span> <span class=\"token punctuation\">{</span> getPrinter <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><br><span class=\"token comment\">// elsewhere...</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>getPrinter<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'printer'</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>formatters<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'formatter-markdown'</span><br><br><span class=\"token keyword\">const</span> myPrinter <span class=\"token operator\">=</span> <span class=\"token function\">getPrinter</span><span class=\"token punctuation\">(</span>formatters<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>opts<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><br><br>myPrinter<span class=\"token punctuation\">.</span><span class=\"token function\">print</span><span class=\"token punctuation\">(</span>dataFromNotion<span class=\"token punctuation\">)</span></code></pre>\n<p>This allows me the freedom to rewrite the <code>Printer</code> however I want (e.g. with closures instead of a <code>class</code>) without having to update everywhere the class is accessed. It also removes any ambiguity about how to instantiate a <code>Printer</code> (though I don’t think I’ve ever had that problem, it’s something I’ve constantly read about in articles and books).</p>\n<p>At this point, we have all the code needed to transform the blocks we get back from Notion into block-level content. Formatting inline content, however, is a bit trickier.</p>\n<h2 id=\"rich-text-formatting\" tabindex=\"-1\">Rich text formatting<a class=\"c-anchor-link\" href=\"#rich-text-formatting\" aria-label=\"permalink\" aria-describedby=\"rich-text-formatting\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In the Notion API, inline content is split into arrays of <a href=\"https://developers.notion.com/reference/rich-text\">rich text objects</a>. Like block objects, each rich text object contains a type (<code>&quot;text&quot;</code>, <code>&quot;mention&quot;</code> and <code>&quot;equation&quot;</code>) and corresponding configuration. Additionally, each contains an <a href=\"https://developers.notion.com/reference/rich-text#annotations\">annotations</a> object, which includes all the local styling information:</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">[</span><br>  <span class=\"token punctuation\">{</span><br>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">,</span><br>    <span class=\"token property\">\"text\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"content\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"This is an example \"</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token property\">\"annotations\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"bold\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"italic\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"strikethrough\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"underline\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"code\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"color\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"default\"</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    ...<br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">{</span><br>    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">,</span><br>    <span class=\"token property\">\"text\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"content\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"of rich text objects.\"</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token property\">\"annotations\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"bold\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"italic\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"strikethrough\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"underline\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"code\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"color\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"default\"</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    ...<br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">]</span></code></pre>\n<p>There are two main approaches to applying the annotations to the content fragments. One method is to treat each fragment individually, applying the start and end token for each annotation object. This works great for HTML but breaks Markdown interpretation. Here’s an example of this technique for both HTML (<code>em</code> and <code>strong</code>) and Markdown (<code>*</code> and <code>**</code>) using the previous rich text objects:</p>\n<pre class=\"language-markdown\"><code class=\"language-markdown\"><span class=\"token comment\">&lt;!-- this works with HTML --></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>em</span><span class=\"token punctuation\">></span></span>This is an example <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>em</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>strong</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>em</span><span class=\"token punctuation\">></span></span>of rich text objects.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>em</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>strong</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token comment\">&lt;!-- whitespace and adjacent duplicate tokens break Markdown interpretation --></span><br><span class=\"token italic\"><span class=\"token punctuation\">*</span><span class=\"token content\">This is an example </span><span class=\"token punctuation\">*</span></span><span class=\"token bold\"><span class=\"token punctuation\">**</span><span class=\"token content\"><span class=\"token italic\"><span class=\"token punctuation\">*</span><span class=\"token content\">of rich text objects.</span><span class=\"token punctuation\">*</span></span></span><span class=\"token punctuation\">**</span></span></code></pre>\n<p>The first fragment ends with whitespace, so the first group of italic tokens (<code>*</code>) isn’t properly interpreted in Markdown. We could check for whitespace at the end of each fragment, pop it off, add the token, then reapply the whitespace, but that would break continuous styles like <code>strikethrough</code>. The best fix is to span tokens of adjacent fragments with duplicate styles.</p>\n<pre class=\"language-markdown\"><code class=\"language-markdown\"><span class=\"token comment\">&lt;!-- now works with italics tokens spanning the entire line --></span><br><span class=\"token italic\"><span class=\"token punctuation\">*</span><span class=\"token content\">This is an example <span class=\"token bold\"><span class=\"token punctuation\">**</span><span class=\"token content\">of nested styling.</span><span class=\"token punctuation\">**</span></span></span><span class=\"token punctuation\">*</span></span></code></pre>\n<p>This method involves analyzing rich text objects in possible groups of three: the current object we are formatting, as well as the previous and following objects (if they exist). For each <code>true</code> annotation for the current object, if the previous object doesn’t have the current annotation, we add the beginning token. If the next object doesn’t have the current annotation, we add the ending token.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\">richTextObjects<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> type<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> config<span class=\"token punctuation\">,</span> annotations <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> i</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">let</span> formatted <span class=\"token operator\">=</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> prev <span class=\"token operator\">=</span> richTextObjects<span class=\"token punctuation\">[</span>i <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> next <span class=\"token operator\">=</span> richTextObjects<span class=\"token punctuation\">[</span>i <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>annotations<span class=\"token punctuation\">.</span>italic<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> startToken <span class=\"token operator\">=</span> <span class=\"token operator\">!</span>prev<span class=\"token operator\">?.</span>annotations<span class=\"token punctuation\">.</span>italic <span class=\"token operator\">?</span> <span class=\"token string\">'*'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">const</span> endToken <span class=\"token operator\">=</span> <span class=\"token operator\">!</span>next<span class=\"token operator\">?.</span>annotations<span class=\"token punctuation\">.</span>italic <span class=\"token operator\">?</span> <span class=\"token string\">'*'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br>    <br>    formatted <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>startToken<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>config<span class=\"token punctuation\">.</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>endToken<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>annotations<span class=\"token punctuation\">.</span>bold<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> startToken <span class=\"token operator\">=</span> <span class=\"token operator\">!</span>prev<span class=\"token operator\">?.</span>annotations<span class=\"token punctuation\">.</span>bold <span class=\"token operator\">?</span> <span class=\"token string\">'**'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">const</span> endToken <span class=\"token operator\">=</span> <span class=\"token operator\">!</span>next<span class=\"token operator\">?.</span>annotations<span class=\"token punctuation\">.</span>bold <span class=\"token operator\">?</span> <span class=\"token string\">'**'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br>    <br>    formatted <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>startToken<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>config<span class=\"token punctuation\">.</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>endToken<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <span class=\"token comment\">// ...link, striketrhough, etc.</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>This logic is not only used to apply the annotation tokens but the link tokens as well. To DRY up this code, I’ve abstracted out the token creation into a factory:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">function</span> <span class=\"token function\">createFormatFactory</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">current<span class=\"token punctuation\">,</span> prev<span class=\"token punctuation\">,</span> next</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">key<span class=\"token punctuation\">,</span> startToken<span class=\"token punctuation\">,</span> endToken <span class=\"token operator\">=</span> startToken</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> pre <span class=\"token operator\">=</span> current<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token operator\">!</span>prev<span class=\"token operator\">?.</span><span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">?</span> startToken <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">const</span> post <span class=\"token operator\">=</span> current<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token operator\">!</span>next<span class=\"token operator\">?.</span><span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">?</span> endToken <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">content</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>pre<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>post<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>This factory is basically three functions that gradually apply formatting arguments in separate layers. Each formatting function needs a current, previous, and next source object (for the styles, it’s the <code>annotations</code> object, and for the link, it’s the rich text object’s type configuration), so that layer is captured first.</p>\n<p>The next layer defines the source object’s <code>key</code> and what tokens to apply. Note that the <code>endToken</code> defaults to the <code>startToken</code> so I don’t have to pass in two <code>*</code> tokens for <code>italic</code>, two <code>**</code> tokens for <code>bold</code>, etc.</p>\n<p>Finally, the last layer applies the derived tokens to some content. Here’s an example of using this factory to create and apply an <code>italic</code> style:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><br><span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> <span class=\"token string\">'This is some content'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> annotations <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">italic</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> previousAnnotations <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">italic</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> nextAnnotations <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">italic</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> formatFromAnnotations <span class=\"token operator\">=</span> <span class=\"token function\">createFormatFactory</span><span class=\"token punctuation\">(</span><br>  annotations<span class=\"token punctuation\">,</span><br>  previousAnnotations<span class=\"token punctuation\">,</span><br>  nextAnnotations<br><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> italic <span class=\"token operator\">=</span> <span class=\"token function\">formatFromAnnotations</span><span class=\"token punctuation\">(</span><span class=\"token string\">'italic'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'*'</span><span class=\"token punctuation\">)</span><br><br><span class=\"token function\">italic</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span> <span class=\"token comment\">// '*This is some content*\"</span></code></pre>\n<p>We will eventually end up with a group of formatter functions that will be applied in a fixed order. We start with <code>code</code> since nesting any tokens inside of a <code>code</code> style will not be interpreted by Markdown. Application with a fixed order along with spanning styles creates certain edge cases that will break (e.g. a <code>code</code> spanning over a <code>link</code>). In practice, these edge cases have been few and far between, so I am choosing to ignore them right now.</p>\n<p>When applying multiple functions to a single source, I immediately reach for a <code>compose</code> function, which simply composes multiple functions together. Using some more recent JavaScript, creating a <code>compose</code> function is trivial:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">function</span> <span class=\"token function\">compose</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token operator\">...</span>fns</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">x</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> fns<span class=\"token punctuation\">.</span><span class=\"token function\">reduceRight</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">acc<span class=\"token punctuation\">,</span> fn</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">fn</span><span class=\"token punctuation\">(</span>acc<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Here is a comparison of applying several functions inline versus using compose:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">fn1</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">arg</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span><span class=\"token punctuation\">}</span><br><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">fn2</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">arg</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span><span class=\"token punctuation\">}</span><br><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">fn3</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">arg</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span><span class=\"token punctuation\">}</span><br><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">fn4</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">arg</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">const</span> result <span class=\"token operator\">=</span> <span class=\"token function\">fn4</span><span class=\"token punctuation\">(</span><span class=\"token function\">fn3</span><span class=\"token punctuation\">(</span><span class=\"token function\">fn2</span><span class=\"token punctuation\">(</span><span class=\"token function\">fn1</span><span class=\"token punctuation\">(</span>someArg<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><br><br><span class=\"token keyword\">const</span> composedResult <span class=\"token operator\">=</span> <span class=\"token function\">compose</span><span class=\"token punctuation\">(</span>fn4<span class=\"token punctuation\">,</span> fn3<span class=\"token punctuation\">,</span> fn2<span class=\"token punctuation\">,</span> fn1<span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span>someArg<span class=\"token punctuation\">)</span></code></pre>\n<p>Notice that we apply the functions from right to left, mimicking the order they appear when composing them inline. That is why we use <code>Array.prototype.reduceRight</code> in the definition of <code>compose</code>. This convenience method allows us to reduce an array in reverse order.</p>\n<aside class=\"c-post__aside c-post__aside--info\"><p>The <code>compose</code> function is a <a href=\"https://en.wikipedia.org/wiki/Functional_programming\">functional programming</a> technique that can be quite useful when you need to combine several pieces of functionality flexibly. Similarly, <a href=\"https://itnext.io/write-better-javascript-function-composition-with-pipe-and-compose-93cc39ab16ee\"><code>pipe</code></a> composes several functions, but in a left-to-right direction.</p>\n</aside>\n<p>Now that we have the basis for our inline formatting logic, we can put the pieces together in our <code>formatRichText</code> function:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><br><span class=\"token keyword\">function</span> <span class=\"token function\">formatRichText</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">richTextObjects <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> richTextObjects<br>    <span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> type<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> config<span class=\"token punctuation\">,</span> annotations <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> i</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>type <span class=\"token operator\">!==</span> <span class=\"token string\">'text'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// TODO: support `mention` and `equation`</span><br><br>      <span class=\"token keyword\">const</span> prev <span class=\"token operator\">=</span> richTextObjects<span class=\"token punctuation\">[</span>i <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">const</span> next <span class=\"token operator\">=</span> richTextObjects<span class=\"token punctuation\">[</span>i <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>      <span class=\"token keyword\">const</span> formatFromConfig <span class=\"token operator\">=</span> <span class=\"token function\">createFormatFactory</span><span class=\"token punctuation\">(</span><br>        config<span class=\"token punctuation\">,</span><br>        prev<span class=\"token operator\">?.</span><span class=\"token punctuation\">[</span>prev<span class=\"token operator\">?.</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br>        next<span class=\"token operator\">?.</span><span class=\"token punctuation\">[</span>next<span class=\"token operator\">?.</span>type<span class=\"token punctuation\">]</span><br>      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">const</span> formatFromAnnotations <span class=\"token operator\">=</span> <span class=\"token function\">createFormatFactory</span><span class=\"token punctuation\">(</span><br>        annotations<span class=\"token punctuation\">,</span><br>        prev<span class=\"token operator\">?.</span>annotations<span class=\"token punctuation\">,</span><br>        next<span class=\"token operator\">?.</span>annotations<br>      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>      <span class=\"token keyword\">const</span> link <span class=\"token operator\">=</span> <span class=\"token function\">formatFromConfig</span><span class=\"token punctuation\">(</span><span class=\"token string\">'link'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'['</span><span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">](</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>config<span class=\"token punctuation\">.</span>link<span class=\"token operator\">?.</span>url<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">)</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">const</span> bold <span class=\"token operator\">=</span> <span class=\"token function\">formatFromAnnotations</span><span class=\"token punctuation\">(</span><span class=\"token string\">'bold'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'**'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">const</span> italic <span class=\"token operator\">=</span> <span class=\"token function\">formatFromAnnotations</span><span class=\"token punctuation\">(</span><span class=\"token string\">'italic'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'*'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">const</span> strikethrough <span class=\"token operator\">=</span> <span class=\"token function\">formatFromAnnotations</span><span class=\"token punctuation\">(</span><span class=\"token string\">'strikethrough'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'~~'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token keyword\">const</span> underline <span class=\"token operator\">=</span> <span class=\"token function\">formatFromAnnotations</span><span class=\"token punctuation\">(</span><span class=\"token string\">'underline'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// no-op for Markdown</span><br>      <span class=\"token keyword\">const</span> code <span class=\"token operator\">=</span> <span class=\"token function\">formatFromAnnotations</span><span class=\"token punctuation\">(</span><span class=\"token string\">'code'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'`'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>      <span class=\"token keyword\">const</span> formatter <span class=\"token operator\">=</span> <span class=\"token function\">compose</span><span class=\"token punctuation\">(</span><br>        link<span class=\"token punctuation\">,</span><br>        bold<span class=\"token punctuation\">,</span><br>        italic<span class=\"token punctuation\">,</span><br>        strikethrough<span class=\"token punctuation\">,</span><br>        underline<span class=\"token punctuation\">,</span><br>        code<br>      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>      <span class=\"token keyword\">return</span> <span class=\"token function\">formatter</span><span class=\"token punctuation\">(</span>config<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>At this point, we are officially done with step three of our plan. We now have a flexible system for styling block-level content, and an efficient way to format rich text objects. We should have more than enough tooling to take on step two, building the page’s front matter.</p>\n<h2 id=\"the-front-matter\" tabindex=\"-1\">The front matter<a class=\"c-anchor-link\" href=\"#the-front-matter\" aria-label=\"permalink\" aria-describedby=\"the-front-matter\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Front matter is truly a separate concern from the page content, but for the time being, I am choosing to tie front matter generation directly to my Markdown formatting. I’ll explain why in a minute. First, let’s examine what needs to be built.</p>\n<p>The front matter of my page is represented in Notion as <a href=\"https://developers.notion.com/reference/property-value-object\">page properties</a>. Currently, my front matter consists of:</p>\n<ul>\n<li><code>title</code> - This is the title of the page, built from a <a href=\"https://developers.notion.com/reference/property-value-object#title-property-values\"><code>title</code> property</a>.</li>\n<li><code>date</code> - This is the publish date of the article, built from a <a href=\"https://developers.notion.com/reference/property-value-object#date-property-values\"><code>date</code> property</a>.</li>\n<li><code>tags</code> - This is an array of taxonomy used to organize my articles, built from a <a href=\"https://developers.notion.com/reference/property-value-object#multi-select-property-values\"><code>multi_select</code> property</a>.</li>\n<li><code>excerpt</code> - This is a fairly new property that allows me to add a short summary of the article, built from a <a href=\"https://developers.notion.com/reference/property-value-object#rich-text-property-values\"><code>rich_text</code> property</a>.</li>\n</ul>\n<p>When assembled, my typical page front matter looks like this:</p>\n<pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">title</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Here it is: An example article\"</span><br><span class=\"token key atrule\">date</span><span class=\"token punctuation\">:</span> <span class=\"token datetime number\">2022-01-01</span><br><span class=\"token key atrule\">excerpt</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"This is an example of [front matter](https://www.11ty.dev/docs/data-frontmatter/). It supports *rich* text formatting.\"</span><br><span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span><br>  <span class=\"token punctuation\">-</span> example<br>  <span class=\"token punctuation\">-</span> fake</code></pre>\n<p>My front matter is structured to support rich text in my <code>excerpt</code> field, and since I already have a Markdown rich text formatter, I’m going to default to formatting my front matter with Markdown. This is the biggest reason I’m tying front matter generation to the formatter.</p>\n<p>With that in mind, let’s look at the front matter generator:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">function</span> <span class=\"token function\">frontMatter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> title<span class=\"token punctuation\">,</span> date<span class=\"token punctuation\">,</span> excerpt<span class=\"token punctuation\">,</span> tags <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"><br>title: \"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>title<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> plain_text <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> plain_text<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\"<br>date: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>date<span class=\"token punctuation\">.</span>date<span class=\"token operator\">?.</span>start <span class=\"token operator\">||</span> <span class=\"token function\">today</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"><br>excerpt: \"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token function\">formatRichText</span><span class=\"token punctuation\">(</span>excerpt<span class=\"token punctuation\">.</span>rich_text<span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\"<br>tags:<br></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>tags<span class=\"token punctuation\">.</span>multi_select<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> name <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">  - </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>name<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">'\\n'</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"><br>---</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The <code>frontMatter</code> function takes our custom properties object (<code>page.frontMatter</code>) and combines the data with a string template literal. I kept this function simple on purpose because I may at some point decide to use a <a href=\"https://www.11ty.dev/docs/data-frontmatter/#alternative-front-matter-formats\">different format for my front matter</a> altogether.</p>\n<p>As previously mentioned, this function lives with the Markdown content formatter because it relies on <code>formatRichText</code>, but front matter generation is a concern separate from content generation. I’m contemplating pulling the main logic of that function into the <code>Printer</code> class, but that’s a problem for Future Ryan.</p>\n<h2 id=\"revisiting-our-notion-client\" tabindex=\"-1\">Revisiting our Notion client<a class=\"c-anchor-link\" href=\"#revisiting-our-notion-client\" aria-label=\"permalink\" aria-describedby=\"revisiting-our-notion-client\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Now that I have most of the formatting out of the way, I want to pull my client code from <a href=\"https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-1-the-notion-api/\">the previous article in this series</a> into a new module. I’m going to take this time to tweak the code a bit as well. Here’s the entirety of the new client module:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> slugify <span class=\"token keyword\">from</span> <span class=\"token string\">'slugify'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">client<span class=\"token punctuation\">,</span> blockId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  blockId <span class=\"token operator\">=</span> blockId<span class=\"token punctuation\">.</span><span class=\"token function\">replaceAll</span><span class=\"token punctuation\">(</span><span class=\"token string\">'-'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> results <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> client<span class=\"token punctuation\">.</span>blocks<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">.</span><span class=\"token function\">list</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">block_id</span><span class=\"token operator\">:</span> blockId<span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">const</span> childRequests <span class=\"token operator\">=</span> results<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>has_children<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>        <span class=\"token keyword\">const</span> children <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span>client<span class=\"token punctuation\">,</span> block<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>        <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>block<span class=\"token punctuation\">,</span> children <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>      <span class=\"token punctuation\">}</span><br>      <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">const</span> expandedResults <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span>childRequests<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> expandedResults<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">handleClientError</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readPageInfo</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">client<span class=\"token punctuation\">,</span> pageId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> properties <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> client<span class=\"token punctuation\">.</span>pages<span class=\"token punctuation\">.</span><span class=\"token function\">retrieve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">page_id</span><span class=\"token operator\">:</span> pageId<span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> properties<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">handleClientError</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readPage</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">client<span class=\"token punctuation\">,</span> pageId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> pageInfo <span class=\"token operator\">=</span> <span class=\"token function\">readPageInfo</span><span class=\"token punctuation\">(</span>client<span class=\"token punctuation\">,</span> pageId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> pageContent <span class=\"token operator\">=</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span>client<span class=\"token punctuation\">,</span> pageId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>properties<span class=\"token punctuation\">,</span> content<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>pageInfo<span class=\"token punctuation\">,</span> pageContent<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">Name</span><span class=\"token operator\">:</span> title<span class=\"token punctuation\">,</span><br>      <span class=\"token punctuation\">[</span><span class=\"token string\">'Publish Date'</span><span class=\"token punctuation\">]</span><span class=\"token operator\">:</span> date<span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">Excerpt</span><span class=\"token operator\">:</span> excerpt<span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">Tags</span><span class=\"token operator\">:</span> tags<span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> properties<span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">slug</span><span class=\"token operator\">:</span> <span class=\"token function\">getSlug</span><span class=\"token punctuation\">(</span>title<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">frontMatter</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> title<span class=\"token punctuation\">,</span> date<span class=\"token punctuation\">,</span> excerpt<span class=\"token punctuation\">,</span> tags <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>      content<span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">handleClientError</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// TODO: better error handling</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">handleClientError</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">error</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body <span class=\"token operator\">||</span> error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">getClient</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">options</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> client <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Client</span><span class=\"token punctuation\">(</span>options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token literal-property property\">pages</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">pageId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>        <span class=\"token keyword\">return</span> <span class=\"token function\">readPage</span><span class=\"token punctuation\">(</span>client<span class=\"token punctuation\">,</span> pageId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">getSlug</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> title <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token function\">slugify</span><span class=\"token punctuation\">(</span><br>    title<br>      <span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> plain_text <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> plain_text<span class=\"token punctuation\">)</span><br>      <span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><br>      <span class=\"token punctuation\">.</span><span class=\"token function\">toLowerCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">export</span> <span class=\"token punctuation\">{</span> getClient <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>I’m combining the page info and page content methods to return the data structure our <code>Printer.print</code> method expects. I’m also including a <code>slug</code> since it’s a concern closely related to the page’s properties, and it’s much easier to encapsulate two related concerns than it is to expose a method that leaks module details to another module.</p>\n<p>I’m exporting a single method, <code>getClient</code>, that returns a simple namespaced object. This gives me the freedom to add new methods in the future if necessary, or completely reimplement existing methods without having to touch other code.</p>\n<h2 id=\"putting-it-all-together\" tabindex=\"-1\">Putting it all together<a class=\"c-anchor-link\" href=\"#putting-it-all-together\" aria-label=\"permalink\" aria-describedby=\"putting-it-all-together\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>We now have all the major pieces to pull down page data, create the front matter from page properties, and output the page content as Markdown. The final step is to combine these pieces and write the result to a local file. To do that, I’ve written a <code>main</code> function that imports the client and formatting methods and uses Node’s file system module to write the file:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> writeFile<span class=\"token punctuation\">,</span> mkdir <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'fs/promises'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getClient <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./client.mjs'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getPrinter <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./printer.mjs'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> formatters<span class=\"token punctuation\">,</span> frontMatter <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./formatter-markdown.mjs'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">CLIENT_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">CLIENT_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>process<span class=\"token punctuation\">.</span>argv<span class=\"token punctuation\">.</span>length <span class=\"token operator\">&lt;</span> <span class=\"token number\">3</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Usage: npm run publish:page [pageId]\\n'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">return</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">const</span> pageId <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>argv<span class=\"token punctuation\">[</span><span class=\"token number\">2</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> client <span class=\"token operator\">=</span> <span class=\"token function\">getClient</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>    <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token constant\">CLIENT_TOKEN</span><span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">const</span> printer <span class=\"token operator\">=</span> <span class=\"token function\">getPrinter</span><span class=\"token punctuation\">(</span>formatters<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> frontMatter <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> client<span class=\"token punctuation\">.</span>pages<span class=\"token punctuation\">.</span><span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>pageId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">const</span> dir <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">./src/blog/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>data<span class=\"token punctuation\">.</span>slug<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">await</span> <span class=\"token function\">mkdir</span><span class=\"token punctuation\">(</span>dir<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">recursive</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> <span class=\"token function\">writeFile</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>dir<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/index.md</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> printer<span class=\"token punctuation\">.</span><span class=\"token function\">print</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">return</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This function is tied to an npm script, <code>publish:page</code>, and takes a page ID as an argument:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> run publish:page -- <span class=\"token punctuation\">[</span>pageId<span class=\"token punctuation\">]</span></code></pre>\n<p>The script fetches the page data using our client, creates the blog post’s directory using the slug from the page data, then writes the file using our printer class.</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion<a class=\"c-anchor-link\" href=\"#conclusion\" aria-label=\"permalink\" aria-describedby=\"conclusion\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>This article focused on pulling Notion page content down, formatting block and rich text objects to Markdown, and writing that content locally to a new file. I have effectively replaced the Markdown export feature of Notion with something much more custom. I have also highlighted a hand full of techniques aimed at making the code more flexible.</p>\n<p>This feels like a good stopping point, but this is by no means the end of this project. I’ve begun using this script to build my post pages, and I’ve already identified several areas for improvement. I’ll continue to post updates as I come across any bugs or improvements, but you can always get the latest and greatest code from my website’s repo.</p>\n<p>Well, that wraps things up for this post. Thank you for sticking with it all the way through. If you liked this article or found it useful, please share it with a friend, and once you do, <a href=\"https://twitter.com/therealboone\">let me know</a>. It’s free to you and it helps me out tremendously.</p>\n<p>Thanks for stopping by. Until next time!</p>\n<h2 id=\"resources\" tabindex=\"-1\">Resources<a class=\"c-anchor-link\" href=\"#resources\" aria-label=\"permalink\" aria-describedby=\"resources\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>Creating a Next.JS blog with Notion: <a href=\"https://samuelkraft.com/blog/building-a-notion-blog-with-public-api\">https://samuelkraft.com/blog/building-a-notion-blog-with-public-api</a></li>\n<li>Creating a CMS with Appsmith and Notion: <a href=\"https://www.appsmith.com/blog/using-the-notion-api-to-build-a-content-management-system\">https://www.appsmith.com/blog/using-the-notion-api-to-build-a-content-management-system</a></li>\n<li>Creating the Notion API: <a href=\"https://www.notion.so/blog/creating-the-notion-api\">https://www.notion.so/blog/creating-the-notion-api</a></li>\n<li>A Guide to Parsing: Algorithms and Terminology <a href=\"https://tomassetti.me/guide-parsing-algorithms-terminology/\">https://tomassetti.me/guide-parsing-algorithms-terminology/</a></li>\n<li>Manipulating AST with JavaScript <a href=\"https://lihautan.com/manipulating-ast-with-javascript/\">https://lihautan.com/manipulating-ast-with-javascript/</a></li>\n</ul>\n",
      "date_published": "2022-05-05T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/quick-tip-non-standard-npm-module-resolution/",
      "url": "https://www.falldowngoboone.com/blog/quick-tip-non-standard-npm-module-resolution/",
      "title": "Quick tip: Non-standard npm module resolution",
      "content_html": "<p>I’m putting the finishing touches on a publishing script for my blog and ran across an interesting situation. The scripts use native ES modules, but Eleventy, the JavaScript framework my blog uses, currently does not support them. I have to specify that my scripts use ES modules with the <code>.mjs</code> extension.</p>\n<pre class=\"language-text\"><code class=\"language-text\">scripts/<br>└── my-publishing-script/<br>\t\t└── index.mjs</code></pre>\n<p>I like to abstract the internals of a script as much as possible, so I like to utilize Node.js module resolution, which allows you to do stuff like this:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">const</span> library <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'library'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>The assumption is that you’ve already run <code>npm install library</code> and <code>library</code> now lives in your <code>node_modules</code> directory.</p>\n<p>If you’ve ever cracked open one of those libraries and looked at their <code>package.json</code> file, chances are they’re making use of the <code>main</code> field, which instructs Node.js as to where the entry file lives relative to the <code>package.json</code>. By default, Node.js looks for <code>index.js</code>, but it can literally be named anything.</p>\n<p>Going back to my script, since it now has to use the <code>.mjs</code> extension, Node.js no longer automatically resolves it, but I can fix that by adding a <code>package.json</code> to my script’s directory with a single <code>main</code> field:</p>\n<pre class=\"language-text\"><code class=\"language-text\">scripts/<br>└── my-publishing-script/<br>\t\t├── index.mjs<br>\t\t└── package.json</code></pre>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span><br>\t<span class=\"token property\">\"main\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"index.mjs\"</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Now I don’t have to specify the entry file when calling the script:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">node</span> scripts/my-publishing-script</code></pre>\n",
      "date_published": "2022-03-19T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/how-i-solve-complex-problems/",
      "url": "https://www.falldowngoboone.com/blog/how-i-solve-complex-problems/",
      "title": "How I solve complex problems",
      "content_html": "<p>Developers are professional problem solvers. It’s the number one reason I became a developer. I am addicted to the feeling I get from solving problems, and there’s rarely a problem that I shy away from, much to my detriment.</p>\n<p>Early on in my professional career, I took on stories that I thought were interesting problems to solve. Unfortunately, <em>I lacked a strong framework to help me deal with the complexity many of these stories presented.</em> The result was missed deadlines and overcomplicated solutions.</p>\n<p>This is something I see in many developers starting out. <em>They want to solve big, interesting problems, but they haven’t developed the tools and the intuition necessary to do so in a timely, well-organized manner.</em> If you’re just starting out, I would encourage you to <strong>develop a problem-solving framework that works for you.</strong></p>\n<p>After my first performance review highlighted my issue with complex problems, I decided to be more intentional with how I approached problems. I developed a personal problem solving framework with the help of my manager, and have continued to refine it with the help of books and articles I’ve read, along with experience I’ve gained working with other developers.</p>\n<p>My framework in summary is as follows:</p>\n<ol>\n<li>Break the problem down</li>\n<li>Hardest problem first</li>\n<li>Work in intervals</li>\n<li>If you get stuck, talk to a duck</li>\n</ol>\n<p>Let’s examine these steps in more detail.</p>\n<h2 id=\"break-the-problem-down\" tabindex=\"-1\">Break the problem down<a class=\"c-anchor-link\" href=\"#break-the-problem-down\" aria-label=\"permalink\" aria-describedby=\"break-the-problem-down\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Complex problems can seem impossible to solve, but they’re really a string of simple problems tangled up in a knot. The first step to solving these complex problems is to <strong>loosen the knot.</strong> We can do that by attempting to pick out the simple problems we already know how to solve.</p>\n<p>Given a customer’s cart, which consists of items with a <code>quantity</code> and a <code>price</code>, how would you determine the total cart price? One way of breaking this problem down would be:</p>\n<ol>\n<li>Iterate through each cart item</li>\n<li>For each item, multiply the <code>quantity</code> and <code>price</code></li>\n<li>Combine the item total of each result</li>\n</ol>\n<p>A side effect of breaking problems down is you have effectively written psuedo-code that can translate directly to your solution:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// iterate through each cart item</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">iterate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">items<span class=\"token punctuation\">,</span> callback</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">let</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> l <span class=\"token operator\">=</span> items<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> l<span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token function\">callback</span><span class=\"token punctuation\">(</span>items<span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><br>\t<span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// for each item, multiply the quantity and price</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">itemTotal</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>quantity<span class=\"token punctuation\">,</span> price<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">return</span> quantity <span class=\"token operator\">*</span> price<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><br><span class=\"token comment\">// combine the item total of each result</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">combineTotals</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">totals</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">return</span> totals<span class=\"token punctuation\">.</span><span class=\"token function\">reduce</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">a<span class=\"token punctuation\">,</span> b</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> a <span class=\"token operator\">+</span> b<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// let's put it all together...</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">cartTotal</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">items</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">const</span> totals <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token function\">iterate</span><span class=\"token punctuation\">(</span>items<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">item</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> totals<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token function\">itemTotal</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token keyword\">return</span> <span class=\"token function\">combineTotals</span><span class=\"token punctuation\">(</span>totals<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Granted, this may not be the most efficient to get a cart total, but it works. You can always work on optimizations once you have a working solution (but that’s for another article).</p>\n<p>Maybe calculating a customer’s cart total isn’t a complex problem to you, but this same approach works for anything from sorting search results by relevance to <a href=\"https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-1-the-notion-api/\">utilizing an API to build blog posts</a> (shameless plug).</p>\n<p>When breaking a problem down, I don’t stop at my initial steps. <strong>I evaluate my proposed solution with a series of questions:</strong></p>\n<ul>\n<li><em>Can I solve each problem? If not, can I break these problems down even more?</em></li>\n<li><em>What assumptions am I making about this problem? Can I prove each assumption?</em></li>\n<li><em>Is there any risk associated with solving this problem? Am I touching shared code? Is there a solution where I don’t touch shared code?</em></li>\n<li><em>Is there a simpler way to break this problem down? Is this solution too complex?</em></li>\n</ul>\n<p>If I’m unsure about anything in the plan, I bring in another team member and walk them through the context. My current team is even experimenting with doing this as a team for stories of significant complexity. Many times different team members will have insight into areas of hidden complexity others may not be aware of.</p>\n<h2 id=\"hardest-problem-first\" tabindex=\"-1\">Hardest problem first<a class=\"c-anchor-link\" href=\"#hardest-problem-first\" aria-label=\"permalink\" aria-describedby=\"hardest-problem-first\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Once I have a plan together, I can start executing it, but not necessarily in the order it’s written. I prefer a testing technique I adapted from the excellent online course <a href=\"https://www.coursera.org/learn/learning-how-to-learn\"><em>Learning How to Learn</em></a> that may seem counterintuitive.</p>\n<p><strong>I start with what I believe is the most difficult problem,</strong> get as far as I can as quickly as possible, and <strong>when I can go no further, I tackle the easiest problem.</strong> When that problem is done, I switch back to the difficult problem, get a bit further, then tackle the next-easiest problem if I hit another dead end. I repeat this process until all of the problems are solved.</p>\n<p>The first reason to start with a hard problem then move to an easy one is it optimizes the total solution time. Switching to other problems and quickly knocking them out ensures <strong>every step of the overall solution will have at least some work done,</strong> even if I end up getting <em>really</em> stuck (more on that later).</p>\n<p>This technique also optimizes brain power. According to <em>Learning How to Learn</em>, our brains have two basic modes of activity: a <strong>focus mode,</strong> where the brain focuses its raw power on a single thought, and a <strong>diffuse mode,</strong> where thoughts bounce all over the brain, connecting seemingly unrelated chunks of thought. Research has shown that the brain works best when <em><strong>switching between these two modes constantly.</strong></em></p>\n<p>Why is that? If you flex a muscle group as hard as you can for an extended period of time, it will fatigue, no matter how well-developed that muscle is. Your brain’s focus mode is like flexing a muscle. Switching to the diffuse mode is like resting that muscle. In addition to rest, the diffuse mode is also responsible for finding novel solutions to problems, which may help you solve your problem faster.</p>\n<h2 id=\"work-in-intervals\" tabindex=\"-1\">Work in intervals<a class=\"c-anchor-link\" href=\"#work-in-intervals\" aria-label=\"permalink\" aria-describedby=\"work-in-intervals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Switching to easier problems helps create space for the brain to rest, but we also need <em>actual</em> rest. I have ADHD, so my work habits swing wildly from completely unfocused to obsessive hyper-focus. Before I know it, five hours have blown by and I’m exhausted. The <a href=\"https://francescocirillo.com/pages/pomodoro-technique\">Pomodoro Technique</a> has been effective in lessening these wild swings and helping me focus on work in a healthy, balanced way.</p>\n<p>Developed in the 1980s by Francesco Cirillo, the Pomodoro Technique calls for 25 minute blocks of focused, uninterrupted work followed by a short break. After completing four cycles of uninterrupted work, <em>take a longer break.</em> There’s a bit more to the technique itself, but at its core, <strong>it’s about splitting deep work up into manageable blocks,</strong> giving your mind the time to rest and maybe even explore alternative solutions.</p>\n<p>What should you do during your break? I personally like to grab a coffee, a snack or work on a Sudoku. I’ve even taken up <a href=\"https://www.quordle.com/\">Quordle</a>, which I find quite fascinating. Really anything I can do in a short amount of time that <em>distracts me from work.</em></p>\n<p>If I feel like I’m losing momentum or discover a new issue that further complicates the problem, I will take some time before a new pomodoro to <strong>reevaluate my strategy</strong> (see the previous questions in Break the problem down). Sometimes, however, I find myself completely stuck. That leads me to my last problem-solving strategy.</p>\n<h2 id=\"if-you-get-stuck%2C-talk-to-a-duck\" tabindex=\"-1\">If you get stuck, talk to a duck<a class=\"c-anchor-link\" href=\"#if-you-get-stuck%2C-talk-to-a-duck\" aria-label=\"permalink\" aria-describedby=\"if-you-get-stuck%2C-talk-to-a-duck\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>You may have heard of rubber ducking before. It comes from a story in the fantastic book <em><a href=\"https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/\">The Pragmatic Programmer</a></em> (highly recommend) where a developer would carry around a rubber duck and explain their code to it line-by-line. I don’t have a rubber duck, but the concept has stuck with me ever since I first read that.</p>\n<p>Many times I will <strong>reiterate the problem to myself</strong> or, much to her chagrin, my wife. Sometimes reiterating the problem at this stage can uncover things you missed in your initial definition of the problem itself, or you can get confirmation that you need someone else to check your work.</p>\n<p>If I’m still stuck, I pull another developer into the conversation (if I paired with a developer on my initial strategy, I talk to that person). I explain the context of the problem and lead them line-by-line in what I’ve done so far. <em>I can’t tell you how many times a fellow developer’s question has unlocked a path to a solution.</em></p>\n<p>It’s important to note that the quicker you get help, the quicker you’ll get to a solution. I tend to want to solve all the problems by myself, but sometimes that’s not possible. The lesson to learn here is <strong>don’t let your ego stand between you and a solution.</strong> Knowing when to ask for help is a mark of a mature developer (not that I’m consistent in this area).</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion<a class=\"c-anchor-link\" href=\"#conclusion\" aria-label=\"permalink\" aria-describedby=\"conclusion\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Solving complex problems is something every developer will do. A solid problem-solving framework can help you create better solutions within the tightest of deadlines. <strong>Be intentional and leave your ego at the door.</strong> The more you develop your framework, the more effective you’ll become.</p>\n<p>Do you have a problem-solving framework? If so, <a href=\"https://twitter.com/therealboone\"><strong>I’d love to know what’s worked for you</strong></a>. I’m always interested in new approaches that could help me grow as a problem solver.</p>\n<p>Until next time!</p>\n",
      "date_published": "2022-03-12T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/preserve-intent-with-architecture-decision-records/",
      "url": "https://www.falldowngoboone.com/blog/preserve-intent-with-architecture-decision-records/",
      "title": "Preserve intent with architecture decision records",
      "content_html": "<p>The first thing I want to do when I dig into a new codebase is learn everything about it. The second thing I want to do is rewrite it. Whether you’re trying to do the former or the latter, architecture decision records (ADRs) can help.</p>\n<p>I was first introduced to ADRs at The Container Store, where the technology department adopted them as a way to record large tech decisions, mostly around microservices architecture. My team  adopted ADRs as a way to record front-end architecture decisions for the e-commerce site as well.</p>\n<p>As I write this, I’m working on my current team’s first ADR. As part of that exercise, I wanted to write out what I understand about ADRs and how they’ve been helpful to me in the past.</p>\n<h2 id=\"what-is-an-architecture-decision-record%3F\" tabindex=\"-1\">What is an architecture decision record?<a class=\"c-anchor-link\" href=\"#what-is-an-architecture-decision-record%3F\" aria-label=\"permalink\" aria-describedby=\"what-is-an-architecture-decision-record%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>An architecture decision record is a document that records a decision. More than that, ADRs capture context such as the problems a decision is meant to address, alternative solutions, and why this decision was chosen.</p>\n<p>In addition to decisions and context, ADRs typically contain decision consequences, both good and bad. Every decision has trade offs, and listing them alongside benefits sheds light on possible concerns to watch for.</p>\n<p>As far as ADR structure, there are several <a href=\"https://github.com/joelparkerhenderson/architecture-decision-record#adr-example-templates\">examples of templates</a> freely available. The first article I ever read on <a href=\"https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions\">documenting architecture decisions</a>, written by Michael Nygard, is even written as an ADR.</p>\n<h2 id=\"benefits\" tabindex=\"-1\">Benefits<a class=\"c-anchor-link\" href=\"#benefits\" aria-label=\"permalink\" aria-describedby=\"benefits\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>For small decisions, informative code comments are great. But when you are adopting a practice throughout a project or department, decision records are the best way to communicate publicly what decision is being made and why.</p>\n<p>ADRs make the decision process transparent. Many times writing an ADR involves the entire team or department, so everyone has an opportunity to explore the decision and understand why it’s being made. This inclusion can increase decision buy-in and alignment as well, since everyone is signing off on it.</p>\n<p>Decision records can be a great onboarding tool as well. Seeing a complete record of decisions can help developers quickly come up to speed on a project. Reading ADRs is much more productive than digging through years of commit history (your team writes <a href=\"https://www.falldowngoboone.com/blog/how-to-get-your-pull-request-merged/#follow-commit-message-standards\">informative commit messages</a>, right?).</p>\n<p>Changing code is risky, and not knowing why the code exists makes any change even riskier. Why spend time to rewrite a layer of architecture only to realize after the work is complete that there are holes in the implementation?</p>\n<p>Finally, a side benefit of writing an ADR is it’s an opportunity for the author to work on their communication skills. I’ve written before about why I believe <a href=\"https://www.falldowngoboone.com/blog/what-is-your-code-communicating/\">communication is one of the most important skills</a> for a developer to…develop. ADRs give developers a chance to communicate complex issues in an easy-to-read manner, as well as develop their ability to argue for a solution.</p>\n<h2 id=\"decision-record-tips\" tabindex=\"-1\">Decision record tips<a class=\"c-anchor-link\" href=\"#decision-record-tips\" aria-label=\"permalink\" aria-describedby=\"decision-record-tips\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you want to get started with ADRs, the easiest way is to find something undocumented that everyone’s already doing and try writing an ADR for that. You’ll be surprised what you’ll learn when exploring the context and consequences of any decision. You may even stumble upon a better solution.</p>\n<p>Whatever the solution is, involve the entire team. Open up a request for comments (RFC) on the decision and make sure everyone is on board. If you can, try to involve every interested engineer in your department. Different engineers bring different perspectives and experience to the table. The more diverse perspectives, the better the decision.</p>\n<p>My final tip is to make your ADRs visible and easy to search. You may want to save your ADRs directly to a repo, or maybe add them to a company wiki. Whatever you do, get a consensus on how to create ADRs (maybe write an ADR on that?). At The Container Store, one of my colleagues built a Ruby on Rails CRUD app that streamlined drafting ADRs directly to a PR in a decision record repo, which kinda made it fun to write ADRs.</p>\n<h2 id=\"what-are-you-waiting-for%3F\" tabindex=\"-1\">What are you waiting for?<a class=\"c-anchor-link\" href=\"#what-are-you-waiting-for%3F\" aria-label=\"permalink\" aria-describedby=\"what-are-you-waiting-for%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Architecture decision records capture decisions, but they also capture the context and consequences of those decisions. ADRs can make the decision process more transparent, increase developer alignment and help onboard new developers. They can even help develop your communication skills. What’s not to love?</p>\n<p>If you’ve read this far, my guess is you’re considering adopting ADRs as a practice on your team. My opinion is you should try them. At the very least you’ll start a conversation with your teammates. There’s a good chance, however, that you’ll introduce a productive practice that will endure long after you’ve left.</p>\n",
      "date_published": "2022-03-05T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-1-the-notion-api/",
      "url": "https://www.falldowngoboone.com/blog/from-notion-to-eleventy-part-1-the-notion-api/",
      "title": "From Notion to Eleventy part 1: The Notion API",
      "content_html": "<p>Notion allows me to collect, organize, and flesh out blog post ideas in a single place, but my painfully manual process of moving from Notion into Eleventy needs work. In this post, the first of a series, I’m going to crack open Notion’s API and see if there’s a way I can use it to streamline my blog workflow.</p>\n<p>Since I’ve never used the Notion API before, I need to come up with a plan. After reading Notion’s excellent <a href=\"https://developers.notion.com/docs/getting-started\">API Getting Started guide</a>, I have an initial strategy.</p>\n<ol>\n<li>Create an integration.</li>\n<li>Connect the integration with my Articles database.</li>\n<li>Install the Notion JavaScript client in my Eleventy project.</li>\n<li>Test the API.</li>\n<li>Explore work flow ideas.</li>\n</ol>\n<p>After I’ve established how to use the API, I’ll have a better idea how to build out a full publishing workflow, which I will implement in the next article. Let’s get started!</p>\n<aside class=\"c-post__aside c-post__aside--info\"><p>If you haven’t already, be sure to check it out my recent article on <a href=\"https://www.falldowngoboone.com/blog/how-i-blog-in-2022/\">my current blogging process</a>. I go into more depth about how I set up my blogging Notion.</p>\n</aside>\n<h2 id=\"the-set-up\" tabindex=\"-1\">The set up<a class=\"c-anchor-link\" href=\"#the-set-up\" aria-label=\"permalink\" aria-describedby=\"the-set-up\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In order to use the Notion API, I need to first create an integration. Integrations are the way Notion authorizes API usage for a particular workspace. The instructions to <a href=\"https://developers.notion.com/docs/getting-started#step-1-create-an-integration\">create an integration</a> are fairly straightforward, but you will need to know the permissions you want your integration to have.</p>\n<p>Since my test only involves reading data, I’m only giving my integration the ability to read data. I’m also excluding user information since I’m the only user. In general, you only want to grant the bare minimum permissions (Notion calls them <em>capabilities</em>) you need to accomplish your goal.</p>\n<p><img src=\"assets/integration-permissions.png\" alt=\"A screenshot of my integration’s capabilities. “Read content” is selected under content capabilities and “No user information” is selected under user capabilities.\"></p>\n<p>After creating my integration, I’ll copy and paste the generated token to my local environment for later. If you’re following along, make sure you don’t paste that token into your codebase and commit it to git. Secrets should never be committed to your git history (I’ve learned this lesson the hard way).</p>\n<aside class=\"c-post__aside c-post__aside--info\"><p>If you should ever find yourself in a situation where you’ve committed a secret to your git history, fear not. <strong>As long as you don’t push to a remote branch,</strong> you can <a href=\"https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History\">rewrite your git history</a> with either an amended commit or interactive rebase. Not that I’ve ever had to do that…😬</p>\n</aside>\n<p>Now that I’ve created an integration, I still can’t use it because Notion will only allow access to pages and databases you have explicitly shared with the integration. You can share any page or database within the assigned workspace by navigating to the thing you want to share and clicking the <em>Share</em> button, then <em>Invite</em>. You should see your new integration in the resulting dialog.</p>\n<p>I’ve invited my integration to a parent page of my Articles database. When you connect a page and/or database to an integration, all child entities come along for the ride. Now I have access to all of my articles. Very exciting!</p>\n<h2 id=\"testing-the-api-locally\" tabindex=\"-1\">Testing the API locally<a class=\"c-anchor-link\" href=\"#testing-the-api-locally\" aria-label=\"permalink\" aria-describedby=\"testing-the-api-locally\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>By now I have hopefully integrated Notion’s API with my Articles database. To test out the connection, I’ll first install the convenient <a href=\"https://www.npmjs.com/package/@notionhq/client\">Notion JavaScript client</a> in my blog’s codebase:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> @notionhq/client</code></pre>\n<p>I’ll also create a little sandbox script that will eventually become my publishing script.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// notion.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">NOTION_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">doStuff</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\tconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Notion!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">doStuff</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Whenever I’m creating a script for automation or app integration, I like to start out with a simple script like this. I create a function, then I call that function. I also import whatever dependencies I <em>think</em> I’ll need and set up environment variables. I’ll then run this with <code>node</code>:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\">$ <span class=\"token assign-left variable\">NOTION_TOKEN</span><span class=\"token operator\">=</span>you_super_secret_token <span class=\"token function\">node</span> notion.js<br>Notion<span class=\"token operator\">!</span></code></pre>\n<p>First I want to read my articles database, and for that, I’ll need a database ID. To get a database ID, navigate to the desired database in Notion (make sure to open it as a page if you haven’t already), open the kebab menu in the top righthand corner, and click <em>Copy link</em>. Paste that link somewhere. The portion between the last <code>/</code> and the <code>?</code> is the ID (if you’re looking at a page link, the ID is the bit after the slug).</p>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># for databases</span><br>https://www.notion.so/<span class=\"token operator\">&lt;</span>workspace<span class=\"token operator\">></span>/<span class=\"token operator\">&lt;</span>datbase_id<span class=\"token operator\">></span>?v<span class=\"token operator\">=</span><span class=\"token punctuation\">..</span>.<br><br><span class=\"token comment\"># for pages</span><br>https://www.notion.so/<span class=\"token operator\">&lt;</span>workspace<span class=\"token operator\">></span>/<span class=\"token operator\">&lt;</span>page_slug<span class=\"token operator\">></span>-<span class=\"token operator\">&lt;</span>page_id<span class=\"token operator\">></span></code></pre>\n<p>After I get the ID for my articles database, I can modify the dummy script to read the contents using the Notion API client:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// notion.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">NOTION_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> notion <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Client</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readDatabase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> notion<span class=\"token punctuation\">.</span>databases<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">database_id</span><span class=\"token operator\">:</span> <span class=\"token string\">'6ae47178...'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// Articles database ID</span><br>      <span class=\"token literal-property property\">filter</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>        <span class=\"token literal-property property\">and</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br>          <span class=\"token punctuation\">{</span><br>            <span class=\"token literal-property property\">property</span><span class=\"token operator\">:</span> <span class=\"token string\">'Status'</span><span class=\"token punctuation\">,</span><br>            <span class=\"token literal-property property\">select</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>              <span class=\"token literal-property property\">equals</span><span class=\"token operator\">:</span> <span class=\"token string\">'Published'</span><span class=\"token punctuation\">,</span><br>            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>        <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br>      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">readDatabase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Notice I’m only querying for articles with a <em>Status</em> of <em>Published</em>. You can <a href=\"https://developers.notion.com/reference/post-database-query-filter\">filter for a long list of properties</a>. When I run that script, I can see a successful response (edited for brevity):</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span><br>\t<span class=\"token property\">\"object\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"list\"</span><span class=\"token punctuation\">,</span><br>\t<span class=\"token property\">\"results\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br>\t\t...<br>    <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"object\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"page\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"5b8889e9...\"</span><span class=\"token punctuation\">,</span><br>      ...<br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br>  <span class=\"token property\">\"next_cursor\"</span><span class=\"token operator\">:</span> <span class=\"token null keyword\">null</span><span class=\"token punctuation\">,</span><br>  <span class=\"token property\">\"has_more\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Notion databases contain pages, and database queries return a response with a list of page objects. This is nice, but what I really want to do is read a page. After selecting a random page ID, I adjust my database script to read a page instead:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// notion.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">NOTION_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> notion <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Client</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readPageInfo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> page <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> notion<span class=\"token punctuation\">.</span>pages<span class=\"token punctuation\">.</span><span class=\"token function\">retrieve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">page_id</span><span class=\"token operator\">:</span> <span class=\"token string\">'7b9c0c66ee...'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// An random article</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>page<span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">readPageInfo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Running this script returns a single <a href=\"https://developers.notion.com/reference/page\">page object</a>. Looking at the page object, I can see that all my page properties are here:</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">\"object\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"page\"</span><span class=\"token punctuation\">,</span><br>\t...<br>  <span class=\"token property\">\"properties\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token property\">\"Publish Date\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"%3BkvS\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"date\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"date\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token property\">\"Tags\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"%40GyO\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"multi_select\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"multi_select\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>...<span class=\"token punctuation\">]</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token property\">\"Name\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"title\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"title\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>...<span class=\"token punctuation\">]</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token property\">\"Status\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"prop_2\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"select\"</span><span class=\"token punctuation\">,</span><br>      <span class=\"token property\">\"select\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>\t...<br><span class=\"token punctuation\">}</span></code></pre>\n<p>This is probably what I’ll need to build my post <a href=\"https://www.11ty.dev/docs/data-frontmatter/\">front matter</a>. The page content, however, isn’t included in this response.</p>\n<p>When I first saw this, I was a bit confused (mostly because I wasn’t reading the reference docs), but this makes sense. Page content is relatively unbounded, so you could have thousands upon thousands of pieces of data objects associated with a page object. Returning all of that data in a single response would be disastrous for the API’s network.</p>\n<p>So how do I get to a page’s content? For that, I’ll need to read the page’s child blocks.</p>\n<aside class=\"c-post__aside c-post__aside--info\"><p>If you’re interested in learning more about the design of Notion’s API, checkout their <a href=\"https://www.notion.so/blog/creating-the-notion-api\">breakdown of the API creation process</a>.</p>\n</aside>\n<h2 id=\"reading-page-content\" tabindex=\"-1\">Reading page content<a class=\"c-anchor-link\" href=\"#reading-page-content\" aria-label=\"permalink\" aria-describedby=\"reading-page-content\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In Notion, all content, including pages, are modeled as <a href=\"https://developers.notion.com/reference/block\">blocks</a>. Blocks can contain child blocks, which is the case with pages. We can use the Notion API to query a block’s children like this:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// notion.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">NOTION_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> notion <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Client</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> blocks <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> notion<span class=\"token punctuation\">.</span>blocks<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">.</span><span class=\"token function\">list</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">block_id</span><span class=\"token operator\">:</span> <span class=\"token string\">'7b9c0c66ee...'</span><span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>blocks<span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>The response includes <em>some</em> of the page’s blocks, but not all of them. By design, blocks with children don’t return with their child blocks resolved (again, for data size concerns). They do, however, include a <code>has_children</code> property of <code>true</code>. We can use that property, as well as the block’s <code>block_id</code>, to recursively fetch child blocks.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// notion.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">NOTION_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> notion <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Client</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token comment\">// block ID is now a param</span><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">blockId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\tblockId <span class=\"token operator\">=</span> blockId<span class=\"token punctuation\">.</span><span class=\"token function\">replaceAll</span><span class=\"token punctuation\">(</span><span class=\"token string\">'-'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// strip all dashes</span><br><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> results<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>blocks <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> notion<span class=\"token punctuation\">.</span>blocks<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">.</span><span class=\"token function\">list</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">block_id</span><span class=\"token operator\">:</span> blockId<span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">const</span> expandedResults <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">let</span> block <span class=\"token keyword\">of</span> results<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>has_children<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>        block<span class=\"token punctuation\">.</span>children <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// recursion FTW!</span><br>      <span class=\"token punctuation\">}</span><br><br>      expandedResults<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br><br>    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>blocks<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">results</span><span class=\"token operator\">:</span> expandedResults <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// we need to return something</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token string\">'7b9c0c66ee...'</span><span class=\"token punctuation\">)</span><br>\t<span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>console<span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This successfully returns a block’s children and assigns them to a <code>children</code> property (hooray!). There is a slight problem with this script, however. In the <code>for...of</code> loop, we <code>await</code> the results of the child <code>readBlocks</code> call. The current script execution pauses until the awaited Promise settles, which slows the script down considerably when dealing with a large number of nested blocks.</p>\n<p><img src=\"assets/for-of-loop.png\" alt=\"An illustration showing how script execution is paused while waiting for a response from a nested read, resulting in a long execution time.\"></p>\n<p>We can improve this with <code>Promise.all</code>.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// notion.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">NOTION_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> notion <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Client</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">blockId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  blockId <span class=\"token operator\">=</span> blockId<span class=\"token punctuation\">.</span><span class=\"token function\">replaceAll</span><span class=\"token punctuation\">(</span><span class=\"token string\">'-'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> results<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>blockResponse <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> notion<span class=\"token punctuation\">.</span>blocks<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">.</span><span class=\"token function\">list</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">block_id</span><span class=\"token operator\">:</span> blockId<span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">const</span> childRequests <span class=\"token operator\">=</span> results<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>has_children<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>        <span class=\"token keyword\">const</span> children <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>        <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>block<span class=\"token punctuation\">,</span> children <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>      <span class=\"token punctuation\">}</span><br>      <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">const</span> expandedResults <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span>childRequests<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>blockResponse<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">results</span><span class=\"token operator\">:</span> expandedResults <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token string\">'7b9c0c66ee...'</span><span class=\"token punctuation\">)</span><br>\t<span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>console<span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Notice the results are now mapped to promises (<code>async</code> functions automatically wrap their return values in a promise even if they’re a synchronous value). Each read process is immediately kicked off, and we simply wait for all of them to be resolved before moving on. This is much faster than reading child blocks one request at a time.</p>\n<p><img src=\"assets/promise-all.png\" alt=\"An illustration that shows how we now execute all block reads at the same time to take advantage of async functions, resulting in a much faster script execution.\"></p>\n<p>Now that we have a way to read page properties and page content, we’ll finish up this exercise by writing this information to a local file. For that, we can use node’s <code>fs</code> module:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Client <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@notionhq/client'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> writeFile <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'fs/promises'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> <span class=\"token constant\">NOTION_TOKEN</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> notion <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Client</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token constant\">NOTION_TOKEN</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">blockId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  blockId <span class=\"token operator\">=</span> blockId<span class=\"token punctuation\">.</span><span class=\"token function\">replaceAll</span><span class=\"token punctuation\">(</span><span class=\"token string\">'-'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> results<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>blockResponse <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> notion<span class=\"token punctuation\">.</span>blocks<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">.</span><span class=\"token function\">list</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">block_id</span><span class=\"token operator\">:</span> blockId<span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">const</span> childRequests <span class=\"token operator\">=</span> results<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>has_children<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>        <span class=\"token keyword\">const</span> children <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>        <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>block<span class=\"token punctuation\">,</span> children <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>      <span class=\"token punctuation\">}</span><br>      <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">const</span> expandedResults <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span>childRequests<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>blockResponse<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">results</span><span class=\"token operator\">:</span> expandedResults <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">readPage</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">pageId</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> pageInfo <span class=\"token operator\">=</span> notion<span class=\"token punctuation\">.</span>pages<span class=\"token punctuation\">.</span><span class=\"token function\">retrieve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>    <span class=\"token literal-property property\">page_id</span><span class=\"token operator\">:</span> pageId<span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> pageContents <span class=\"token operator\">=</span> <span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span>pageId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>info<span class=\"token punctuation\">,</span> contents<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>pageInfo<span class=\"token punctuation\">,</span> pageContents<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>info<span class=\"token punctuation\">,</span> contents <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token function\">readPage</span><span class=\"token punctuation\">(</span><span class=\"token string\">'7b9c0c66ee...'</span><span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">writeFile</span><span class=\"token punctuation\">(</span><span class=\"token string\">'test.json'</span><span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<h2 id=\"wrapping-up\" tabindex=\"-1\">Wrapping up<a class=\"c-anchor-link\" href=\"#wrapping-up\" aria-label=\"permalink\" aria-describedby=\"wrapping-up\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>This is a great place to stop for now. To review, I started out by creating an initial plan, then I tackled the plan step-by-step. When I ran into issues (e.g. discovering page objects don’t include content), I amended the plan.</p>\n<p>Now I have a data structure written to a local file that includes everything I need to write a post. The main challenge left, then, is transforming that data into something I can consume in Eleventy. I’ll cover that in my next article.</p>\n<p>I should note I purposely chose a page that was very small and contained simple content. I didn’t want to get bogged down troubleshooting edge cases when all I wanted to do was explore the API. Keep in mind there are <a href=\"https://developers.notion.com/reference/request-limits\">API limits</a>, and if your content is relatively large and complex, you will encounter them at some point.</p>\n<p>Dealing with these limits is outside the scope of this post, but I may in the future write a dedicated post on how to work with API limits (e.g. rate limits, pagination, etc.). If that’s something you’d like to read, let me know!</p>\n<p>If you’ve enjoyed this post, please consider sharing it with others that might like it. And if you have any comments, please <a href=\"https://twitter.com/therealboone\">reach out to me on Twitter</a>. I love to discuss all things front end, and it quite frankly gives me the warm fuzzies to know other people are reading these posts.</p>\n<p>Until next time!</p>\n",
      "date_published": "2022-02-26T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/brad-frost-on-how-to-use-storybook/",
      "url": "https://www.falldowngoboone.com/blog/brad-frost-on-how-to-use-storybook/",
      "title": "Brad Frost on how to use Storybook",
      "content_html": "<p>Brad Frost recently appeared on the <a href=\"https://www.youtube.com/watch?v=jR0Gefa4lpg&amp;t=1s\">new Storytime podcast</a> with Chantastic to talk about how he uses Storybook to build design systems. The show features a great discussion regarding how Frost’s <a href=\"https://bradfrost.com/blog/post/atomic-web-design/\">Atomic Design</a> philosophy has been applied to the popular UI development tool. If you haven’t already, I highly recommend checking the episode out.</p>\n<p>As a follow up to the discussion, Brad wrote a companion article that details <a href=\"https://bradfrost.com/blog/post/atomic-design-and-storybook/\">how he utilizes Storybook in design systems</a>. This article was timely for me, as the team I work on is dealing with a crisis of faith regarding our Storybook implementation.</p>\n<p>Long story short, building stories for our components has been somewhat complicated due to the complexities of our form system. Coupled with the lightning-fast rate we’ve been adding features to existing components, and our Storybook is lacking in-depth and up-to-date information.</p>\n<p>Brad says in his article the he uses Storybook as the official design system, building components exclusively in Storybook, then packaging up the results in a bundle that’s then used as a project dependency. I think this approach would be a great solution to our team’s current lack of interest.</p>\n<p>Of course, this approach slows UI development down, but I would argue that’s a good thing. I personally like to take it slow when creating shared components. Context is key to creating a health component API, and you need to use a component pattern several times before you understand everything that’s required.</p>\n<p>I hope to have a follow up article about this in the future. I’m also planning a series on how I approach component API design and development, so give me a follow on Twitter and DEV Community if that sounds like something you’re interested in.</p>\n<p>In the meantime, be sure to <a href=\"https://www.youtube.com/watch?v=jR0Gefa4lpg&amp;t=1s\">watch the interview</a> and <a href=\"https://bradfrost.com/blog/post/atomic-design-and-storybook/\">read Brad’s article</a>.</p>\n",
      "date_published": "2022-02-18T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/the-one-where-this-is-undefined/",
      "url": "https://www.falldowngoboone.com/blog/the-one-where-this-is-undefined/",
      "title": "The one where &#39;this&#39; is undefined",
      "content_html": "<p>I have been writing JavaScript since…well, let’s just say I was still watching new episodes of <em>Friends</em> on my un-flat CRT television. As long as I’ve worked with JavaScript, I <em>still</em> seem to forget the gotchas around the <code>this</code> keyword.</p>\n<p>Recently I ran into a series of problems involving the <code>this</code> keyword while exploring the Notion API. I thought it’d be Fun™ to take a look at why those problems occurred and how I ultimately resolved them.</p>\n<h2 id=\"the-code\" tabindex=\"-1\">The code<a class=\"c-anchor-link\" href=\"#the-code\" aria-label=\"permalink\" aria-describedby=\"the-code\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Notion’s API has a <em>notion</em> (see what I did there?) of content as blocks. To write a page out, you have to stitch together these blocks in a specific way.</p>\n<p>Each block has a different <code>type</code>, and each <code>type</code> is associated with a different handler. I built a class that takes an object of handlers keyed by these types and got this masterpiece:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Writer</span> <span class=\"token punctuation\">{</span><br>\t#writers<span class=\"token punctuation\">;</span><br><br>\t<span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">writers</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers <span class=\"token operator\">=</span> writers<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>\t<span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t\t<span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>\t\t<span class=\"token punctuation\">}</span><br><br>\t\t<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br>\t\t<span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>\t\t<span class=\"token keyword\">return</span> <span class=\"token function\">writer</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>\t<span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Writer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br>\t<span class=\"token function\">paragraph</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> paragraph <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> text <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> paragraph<span class=\"token punctuation\">;</span> <span class=\"token comment\">// text here is actually an array of blocks</span><br><br>\t\t<span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">&lt;p></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">write</span><span class=\"token punctuation\">(</span>text<span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/p></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span><br>\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>\t<span class=\"token comment\">// ...more handlers...</span><br>\t<span class=\"token function\">text</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> text <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> link<span class=\"token punctuation\">,</span> content <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> text<span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">return</span> link <span class=\"token operator\">?</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">&lt;a href=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>link<span class=\"token punctuation\">.</span>url<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\"></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/a></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">:</span> content<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre>\n<p>Note that the block handlers passed into the <code>Writer</code> class can reference the <code>write</code> function directly. This is a convenience that allows handlers to forward nested block types to the writer for further processing. Neat!</p>\n<p>Here’s my <code>Writer</code> class in action:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">readBlockChildren</span><span class=\"token punctuation\">(</span><span class=\"token string\">'7b9c0c66eebd47c6911ecd7f2defad6b'</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// A Notion API wrapper</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>writer<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>console<span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Looks harmless enough, except we get a nasty error when we run this code:</p>\n<pre class=\"language-text\"><code class=\"language-text\">\t\t\treturn block.map(this.write).join('');<br>                            ^<br><br>TypeError: Cannot read properties of undefined (reading 'write')</code></pre>\n<p>Well that’s rude! Apparently <code>this</code> is <code>undefined</code> inside of the <code>Writer#write</code> method.</p>\n<p>After some investigation, I determined that the error happens right after the first <code>.then</code> call after reading the article blocks:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">readBlockChildren</span><span class=\"token punctuation\">(</span><span class=\"token string\">'7b9c0c66eebd47c6911ecd7f2defad6b'</span><span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>writer<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">)</span> <span class=\"token comment\">// I'm the problem. Hello!</span><br>  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>console<span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Notice I’m using a point-free style to pass my <code>write</code> method to <code>then</code>. I like it because it feels more terse. Don’t judge me.</p>\n<p>We reference <code>this</code> inside of <code>writer.write()</code>. Normally, this wouldn’t be a problem, but passing <code>writer.write</code> point free removes the <code>writer</code> context, leaving <code>this</code> bound to the global context (which is <code>undefined</code> in strict-mode).</p>\n<p>Here’s an illustration of the problem:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">MyClass</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token function\">getContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">const</span> myClass <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">MyClass</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> getContext <span class=\"token operator\">=</span> myClass<span class=\"token punctuation\">.</span>getContext<span class=\"token punctuation\">;</span><br><br>myClass<span class=\"token punctuation\">.</span><span class=\"token function\">getContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token operator\">=></span> MyClass <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><br><span class=\"token function\">getContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">undefined</span></code></pre>\n<p>Passing the <code>write</code> method point-free is the equivalent of assigning it to a variable. No context. Whomp whomp.</p>\n<p>Calling the method inside a callback fixes this particular issue.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">readBlocks</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><br>\t<span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> writer<span class=\"token punctuation\">.</span><span class=\"token function\">write</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><br>\t<span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>console<span class=\"token punctuation\">.</span>log<span class=\"token punctuation\">)</span></code></pre>\n<p>The context is preserved and everyone gets a medal.</p>\n<h2 id=\"a-new-challenger-has-appeared\" tabindex=\"-1\">A new challenger has appeared<a class=\"c-anchor-link\" href=\"#a-new-challenger-has-appeared\" aria-label=\"permalink\" aria-describedby=\"a-new-challenger-has-appeared\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Unfortunately, even though the context is preserved during the first call, running the code again yields this gem:</p>\n<pre class=\"language-text\"><code class=\"language-text\">\t\tconst writer = this.#writers[type];<br>                        ^<br><br>TypeError: Cannot read properties of undefined (reading '#writers')</code></pre>\n<p>The error suggests that <code>this</code> is once again <code>undefined</code>. This seems related to the last problem, but at a different spot. Some more investigation uncovers the location of the cause lies in how I handle arrays in the <code>write</code> method:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// here's the problem</span><br>\t<span class=\"token punctuation\">}</span><br><br>\t<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br>\t<span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token keyword\">return</span> <span class=\"token function\">writer</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Again, I’m using point-free style (I’m the worst), and again the context gets completely lost. The reason is slightly different now, though. <code>Array#map</code> is called with a callback, which by default binds <code>this</code> to <code>undefined</code>.</p>\n<p>One solution is to nest the <code>write</code> method reference inside a callback like previously. There is one caveat: since we are referring to <code>this.write</code> and not a class instance (<code>writer.write</code>), an arrow function is required to maintain the <em>lexical</em>[lexical] <code>this</code> binding.</p>\n<p>[lexical] <em>Lexical</em> is just a fancy way of saying the context of the surrounding scope at the time the scope is being defined, which in this case is the class instance. <em>Lexical</em> is also one of my favorite words. Say it with me: <em>lexical</em>.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token comment\">// this doesn't work</span><br>\t\t<span class=\"token comment\">// return block</span><br>    <span class=\"token comment\">//    .map(function (child) {</span><br>    <span class=\"token comment\">//      return this.write(child);</span><br>    <span class=\"token comment\">//    })</span><br>    <span class=\"token comment\">//    .join('');</span><br><br>\t\t<span class=\"token comment\">// this works</span><br>\t\t<span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">child</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">write</span><span class=\"token punctuation\">(</span>child<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>\t<span class=\"token punctuation\">}</span><br><br>\t<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br>\t<span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token keyword\">return</span> <span class=\"token function\">writer</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>That’s definitely one way of fixing that problem, but a more interesting way is to use the second argument for <code>map</code>, which is the <code>thisArg</code>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token comment\">// this works</span><br>\t\t<span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">,</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>\t<span class=\"token punctuation\">}</span><br><br>\t<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br>\t<span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br>\t<span class=\"token keyword\">return</span> <span class=\"token function\">writer</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Did you know <code>map</code> took a second argument? Yeah, it does. When we pass a <code>thisArg</code> to <code>map</code>, <code>this</code> is then bound to <code>thisArg</code> inside of the <code>map</code> callback. Huzzah!</p>\n<h2 id=\"another-one\" tabindex=\"-1\">Another one<a class=\"c-anchor-link\" href=\"#another-one\" aria-label=\"permalink\" aria-describedby=\"another-one\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Now let’s run that beautiful code.</p>\n<pre class=\"language-text\"><code class=\"language-text\">\t\treturn `<p>${this.write(text)}</p>\\n`;<br>                      ^<br><br>TypeError: Cannot read properties of undefined (reading 'write')</code></pre>\n<p>Okay, I quit.</p>\n<p>Alright, I’m back. This is really a rollercoaster of emotion for me.</p>\n<p>Same issue, different place. It seems like I’ve gotten really good at trying to read properties of <code>undefined</code>. But that’s okay, we will persevere!</p>\n<p>After taking a closer look at the error, it seems like the issue is no longer occurring inside of the <code>write</code> method, which I believe to be a sign of progress. This time, the issue is inside a writer definition.</p>\n<p>If you recall from a previous code block way back near the top of this article (who remembers that far back, anyway?), we pass a map of writers into the <code>Writer</code> class at initialization. These writer methods can <em>also</em> access the <code>write</code> method with <code>this</code> (or, at least that’s how I planned it; in practice they’re doing jack squat).</p>\n<p>The writers need some way to write nested content, so <code>write</code> needs to be present somehow in the writer context.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// a quick reminder of what the writers look like</span><br><span class=\"token keyword\">const</span> writers <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token function\">paragraph</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> paragraph <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t\t<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> text <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> paragraph<span class=\"token punctuation\">;</span><br><br>\t\t<span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">&lt;p></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">write</span><span class=\"token punctuation\">(</span>text<span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/p></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// hey, here's a `this` reference</span><br>\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>\t<span class=\"token comment\">// ...more handlers...</span><br>\t<span class=\"token function\">text</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> text <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> link<span class=\"token punctuation\">,</span> content <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> text<span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">return</span> link <span class=\"token operator\">?</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">&lt;a href=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>link<span class=\"token punctuation\">.</span>url<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\"></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/a></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">:</span> content<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// inside Writer</span><br><span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">,</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// assignment!</span><br><br>  <span class=\"token keyword\">return</span> <span class=\"token function\">writer</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>We assign the writer function to a variable within the class’s <code>write</code> method, but this will not bind the instance context to <code>this</code> inside the writer methods. Why?</p>\n<p>First of all, we’re doing that thing where we blow away context by assigning an instance method to a variable. D’oh!</p>\n<p>Let’s call the method directly and see if that fixes things:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">,</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// writer called directly</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>We still get an error, but it’s a <em>new</em> error message.</p>\n<pre class=\"language-text\"><code class=\"language-text\">\t\treturn `&lt;p>${this.write(text)}&lt;/p>\\n`;<br>                      \t ^<br><br>TypeError: this.write is not a function</code></pre>\n<p>This time <code>this</code> is defined (progress!), but <code>write</code> is not (bummer!). Chalk that up to a change in context.</p>\n<p>The writers are functions defined in an object literal, so <code>this</code> refers to the surrounding object literal, not the parent class instance. If we want to keep the <code>this</code> references in the writer methods, we’ll need to bind the class instance to the method before calling it:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">,</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> writer <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">bind</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">return</span> <span class=\"token function\">writer</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The <code>bind</code> function method takes a <code>thisArg</code> as its first argument and binds that function’s <code>this</code> to that argument’s value (in the case of <code>null</code> or <code>undefined</code>, <code>this</code> defaults to the global execution context). Another interesting use of <code>bind</code> is partial application, but that’s a subject for another day.</p>\n<p>The use of <code>bind</code> fixes our <code>this</code> problem completely, but it might be a bit confusing for other users. Passing the class instance method of <code>write</code> into the writer as a second argument might seem more reasonable:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token function\">write</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>block<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Array<span class=\"token punctuation\">.</span><span class=\"token function\">isArray</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> block<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">,</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> type <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> block<span class=\"token punctuation\">;</span><br><br>\t<span class=\"token comment\">// remember to pass as an arrow function to preserve the current scope!</span><br>  <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>#writers<span class=\"token punctuation\">[</span>type<span class=\"token punctuation\">]</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">block</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">write</span><span class=\"token punctuation\">(</span>block<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>We would then use this write method in the writers.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">const</span> writers <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token function\">paragraph</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> paragraph <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> write</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> <span class=\"token comment\">// write method injected as an argument</span><br>\t\t<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> text <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> paragraph<span class=\"token punctuation\">;</span><br><br>\t\t<span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">&lt;p></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token function\">write</span><span class=\"token punctuation\">(</span>text<span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/p></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// works!</span><br>\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>\t<span class=\"token function\">text</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> text <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> <span class=\"token comment\">// if you don't need the `write` method, don't use it!</span><br>    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> link<span class=\"token punctuation\">,</span> content <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> text<span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">return</span> link <span class=\"token operator\">?</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">&lt;a href=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>link<span class=\"token punctuation\">.</span>url<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\"></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/a></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token operator\">:</span> content<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"making-peace-with-this\" tabindex=\"-1\">Making peace with <code>this</code><a class=\"c-anchor-link\" href=\"#making-peace-with-this\" aria-label=\"permalink\" aria-describedby=\"making-peace-with-this\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The code works now. Hurray! Looks like I <em>won’t</em> be quitting tech, moving to a large, unincorporated rural area and starting my own country in a prepper basement. Today.</p>\n<p>When I started working with JavaScript at an unspecified date in the past, <code>this</code> was one of the most confusing concepts to me. So confusing, in fact, that I avoided it like the plague.</p>\n<p>Thankfully there are tons of great resources available to shed light on <code>this</code>. One of the most helpful resources was Kyle Simpson’s excellent <em>You Don’t Know JS</em> series, especially <em><a href=\"https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/this%20&amp;%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes\">this &amp; Object Prototypes</a></em>. I consumed that book, as well as several other resources (shout out to Frontend Masters!), and <code>this</code> became less confusing to me, and now I use it all over the place (to my own detriment, apparently).</p>\n<p>I guess the point I’m trying to make is not to use <code>this</code> in your every day code; it’s to make peace with the parts of programming that confuse, frustrate, or even frighten you. Understanding core concepts of your programming language of choice empowers you and gives you a better toolset to troubleshoot annoying errors.</p>\n<p>Do you love <code>this</code>? Do you wish <code>this</code> was never included in JavaScript? Even more important, do you have a better pattern for unwinding Notion blocks? <a href=\"https://twitter.com/therealboone\">Let’s discuss on Twitter</a>.</p>\n<p>Until next week!</p>\n",
      "date_published": "2022-02-12T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/how-i-blog-in-2022/",
      "url": "https://www.falldowngoboone.com/blog/how-i-blog-in-2022/",
      "title": "How I blog in 2022",
      "content_html": "<p>It’s a new year, and I’m eager to get back into the habit of blogging on my site. To start, I’m taking another look at my blogging process and what has changed since the last time I wrote about it.</p>\n<h2 id=\"idea-generation\" tabindex=\"-1\">Idea generation<a class=\"c-anchor-link\" href=\"#idea-generation\" aria-label=\"permalink\" aria-describedby=\"idea-generation\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I’ve maintained a blogging Notion for a couple of years now, but I recently adopted <a href=\"https://daverupert.com/2021/09/my-notion-blogging-kanban/\">Dave Rupert’s Notion blogging kanban</a>.</p>\n<figure>\n  <img width=\"1680\" height=\"1050\" src=\"blogging-kanban-optimized.jpg\" alt=\"\">\n  <figcaption>My blogging kanban, which is completely aped from Dave Rupert. Thanks, Dave!</figcaption>\n</figure>\n<p>The kanban has six lanes: <em>No Status</em>, <em>Outlined</em>, <em>Started</em>, <em>Rough Draft</em>, <em>Final Draft</em>, and <em>Published</em>. Ideas get chucked into the <em>No Status</em> lane and slowly make their way from left to right on the board as the post develops.</p>\n<p>Each lane is sorted by <em>Last Updated,</em> which I love. As Dave explains:</p>\n<blockquote>\n<p>This gives me a “What’s hot” vibe for each column. It helps me keep momentum on my latest ideas —a freshness seal— to keep them from falling out of view.</p>\n</blockquote>\n<p>If a story gets too stale or I notice it hasn’t progressed in a while, I archive it, which removes it from the kanban view. I have a separate view for these archived, unpublished ideas, which Dave calls the <em>Deadpool</em>. I’ve added a dedicated view for these in case I need to search through them.</p>\n<p>Like Dave, I’ve also added a view that organizes all my posts by tag. I haven’t used this view much, but it’s nice to see at a glance what topics I tend to favor.</p>\n<h2 id=\"publishing\" tabindex=\"-1\">Publishing<a class=\"c-anchor-link\" href=\"#publishing\" aria-label=\"permalink\" aria-describedby=\"publishing\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Publishing is still as manual as ever. I export the post out of Notion as Markdown and add it to my local website instance. I adjust the front matter, then send it through Grammarly for final corrections.</p>\n<p>After finalizing the article, I commit and open a pull request on GitHub. Pull requests automatically start project tests and spin up a staging site, thanks to Netlify and GitHub actions. After verifying that all is well, I merge into the main branch, and Netlify does the deployment.</p>\n<p>Keeping everything in Notion is great because everything is in the same place. The downside is publishing is still a ridiculously manual process. I plan to address this later this month by checking out <a href=\"https://developers.notion.com\">Notion’s API</a>.</p>\n<h2 id=\"blogging-frequency\" tabindex=\"-1\">Blogging frequency<a class=\"c-anchor-link\" href=\"#blogging-frequency\" aria-label=\"permalink\" aria-describedby=\"blogging-frequency\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>After completing a <a href=\"https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/\">daily blogging challenge last year</a>, I thought seriously about setting a weekly blogging goal. I had written a new piece every day; how hard could it be to move to a weekly schedule? As it turns out, quite hard.</p>\n<p>Life happens, and in 2021 it <em>really</em> happened. I talk more about it in my <a href=\"https://www.falldowngoboone.com/blog/year-end-review-2021/\">2021 year-end review</a>, but I got burned out, lost family members, and started a new job. To say my life was chaotic is a bit of an understatement.</p>\n<p>That’s not to say that I shouldn’t expect to produce content regularly. I stopped writing because I didn’t have a consistent habit. That’s why I like setting blogging challenges. They give me something to aim for, which keeps me focused on the process itself.</p>\n<h2 id=\"other-changes\" tabindex=\"-1\">Other changes<a class=\"c-anchor-link\" href=\"#other-changes\" aria-label=\"permalink\" aria-describedby=\"other-changes\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>When I first launched <a href=\"https://www.falldowngoboone.com/blog/how-im-redesigning-my-blog/\">my latest blog design</a> in 2020, there were more than a few rough edges (by design). I also didn’t know what I wanted because I had never consistently published content.</p>\n<p>After upping my content production, I was able to see <a href=\"https://www.falldowngoboone.com/blog/what-i-learned-blogging-daily-for-a-month/#did-not-work%3A-my-website-styling-is-lacking\">glaring holes in my simple design</a> that needed plugging.</p>\n<p>I made much progress toward plugging those holes in 2021. I shipped several new features, my favorite of which is <a href=\"https://www.falldowngoboone.com\">my new home page</a>. Other shipped features include styling for blockquotes, footnotes, asides, etc.</p>\n<p>I’m looking forward to adding some form content later this year when I add a contact section. I have plans to make it especially fun and (hopefully) educational. I also plan on shipping a dark theme in the next couple of months.</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion<a class=\"c-anchor-link\" href=\"#conclusion\" aria-label=\"permalink\" aria-describedby=\"conclusion\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So that’s a quick look at my blogging process for early 2022. I like doing these because it helps me understand what’s working and what isn’t. I hope you enjoy them too.</p>\n<p>This year should prove interesting. I’ve got some GraphQL and TypeScript content planned, in addition to some of my UI component philosophy. If that sounds like something you’d like to read more about, give me a follow on <a href=\"https://twitter.com/therealboone\">Twitter</a> or <a href=\"https://dev.to/falldowngoboone\">DEV Community</a> to be notified when these posts are published.</p>\n<p>Until next time!</p>\n",
      "date_published": "2022-02-04T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/year-end-review-2021/",
      "url": "https://www.falldowngoboone.com/blog/year-end-review-2021/",
      "title": "Year-end review 2021",
      "content_html": "<p>2021 proved to be an eventful year for many of us. Personally, my year brought tremendous successes, failures, victories, and heartbreak. These last 365 days have felt like an entire lifetime!</p>\n<p>Last year I wrote a similar <a href=\"https://www.falldowngoboone.com/blog/year-end-review-2020/\">year-end review for 2020</a>, where I laid out some 2021 opportunities that I felt were worth pursuing. So how did I do?</p>\n<h2 id=\"2021-opportunities-reviewed\" tabindex=\"-1\">2021 opportunities reviewed<a class=\"c-anchor-link\" href=\"#2021-opportunities-reviewed\" aria-label=\"permalink\" aria-describedby=\"2021-opportunities-reviewed\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>There were a couple of opportunities involving internal tooling at The Container Store. Unfortunately, I wasn’t able to accomplish these goals. Long story short, there were many changes to The Container Store’s leadership in 2021, including a new CEO and CIO, and my priorities changed accordingly. They changed so dramatically, in fact, that <strong>I decided to leave The Container Store in September.</strong></li>\n<li>I also saw an opportunity to start writing more regularly in 2021. In February, I began what I hope is an annual tradition of writing an article a day for an entire month, and I gave it the unfortunate name of <a href=\"https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/\">Blogruary</a>. Many of the posts were cross-posted on <a href=\"https://dev.to/falldowngoboone\">DEV Community</a>, which helped boost the blog’s visibility. <strong>I went from writing three articles in 2020 to writing over 30 articles in 2021!</strong></li>\n<li>Finally, I mentioned I would love to do more speaking engagements, and I’m happy to say <strong>I gave my first virtual conference talk at RailsConf 2021!</strong> It was a great experience, and I’m grateful to the RailsConf team for taking a chance on me.</li>\n</ul>\n<h2 id=\"other-2021-accomplishments\" tabindex=\"-1\">Other 2021 accomplishments<a class=\"c-anchor-link\" href=\"#other-2021-accomplishments\" aria-label=\"permalink\" aria-describedby=\"other-2021-accomplishments\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>\n<p>I mentioned above that I am sadly no longer with The Container Store. My job became something I was no longer enjoying. I will miss my fantastic coworkers, and I wish them all great success.</p>\n<p><strong>I am now a Senior Software Engineer at <a href=\"https://www.yum.com/\">Yum! Brands</a></strong> working on an internal React product, and I’m enjoying every minute of it. In particular, I like working on the API layer, a TypeScript app that accesses a company-wide GraphQL gateway. Lots of opportunity for growth!</p>\n</li>\n<li>\n<p>I also previously mentioned that I started a daily blog challenge in February. Completing that challenge gave me more <a href=\"https://www.falldowngoboone.com/blog/what-i-learned-blogging-daily-for-a-month/\">insight into my blog and blogging process</a>, and I hope to be able to do that again next year.</p>\n<p>Blogruary also grew the blog’s audience. Before February 2020, I averaged about 30–40 users a day. As of December 2021, I’m currently around 600 a day. That’s <strong>a 2000% increase in readership!</strong></p>\n</li>\n<li>\n<p>I have also consistently launched new features on my blog (check out the <a href=\"https://www.falldowngoboone.com/feed/feed.xml\">XML</a> and <a href=\"https://www.falldowngoboone.com/feed/feed.json\">JSON</a> RSS feeds). GitHub Projects has been an enormous help, and I’m starting to use it in all of my projects.</p>\n</li>\n</ul>\n<h2 id=\"2021-challenges\" tabindex=\"-1\">2021 challenges<a class=\"c-anchor-link\" href=\"#2021-challenges\" aria-label=\"permalink\" aria-describedby=\"2021-challenges\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>At the end of 2020, I was hopeful that 2021 would be a much better year, and while I had some incredible experiences, the year was not without its share of setbacks.</p>\n<ul>\n<li>\n<p>In 2021, I experienced burnout at a level I had not had since my days as a designer. I transitioned into managing overseas developers, and most of the work I had previously enjoyed doing moved to those developers. I no longer had time to work on the internal projects that gave me a sense of ownership, and I certainly didn’t have time for continuing education. Work became less about creation/exploration and more about unblocking others.</p>\n<p><strong>I loved the developers I was working with, but I didn’t love the work, and my personal life suffered.</strong> I completely lost interest in anything code-related, including this blog. This apathy was the ultimate momentum that led me to pursue work elsewhere. I can happily say that I’m slowly recovering from the fatigue and am even picking my personal projects back up.</p>\n</li>\n<li>\n<p>On top of burnout, my wife and I experienced a devastating personal loss that’s still difficult for me to talk about. In August, my wife unexpectedly lost her father to COVID-19. He was unvaccinated despite my wife’s constant pleading with him to do so. It’s terrible to lose someone before their time, but it’s even more difficult to deal with grief mixed with anger, especially at the misinformation that’s propagated with the sole purpose to create confusion.</p>\n<p>For now, we’re still taking it one day at a time. Some days are good, some days are not-so-good, but the not-so-good days are growing fewer and farther between.</p>\n</li>\n</ul>\n<h2 id=\"2022-goals\" tabindex=\"-1\">2022 goals<a class=\"c-anchor-link\" href=\"#2022-goals\" aria-label=\"permalink\" aria-describedby=\"2022-goals\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>With 2021 out of the way, I am hoping for a better, brighter 2022. My focus will continue to be growth and learning, but I will also include my health. With everything that’s happened this past year, I’m afraid I haven’t taken care of myself. To that end, here are my personal goals for 2022:</p>\n<ul>\n<li>I published 36 articles in 2021, so in 2022 my goal is to <strong>publish 42 articles, with 28 articles in February (Blogruary), most of which will be cross-posted in DEV Community.</strong></li>\n<li>My goal for the blog is to <strong>finish up all current issues in my projects list.</strong></li>\n<li><strong>Build 3 projects</strong> from my project backlog.</li>\n<li><strong>Work out</strong> at least twice a week, go on at least one 40 minute walk a week.</li>\n<li>This last one’s high on my list. My wife and I want to <strong>get out and explore other places to live,</strong> mostly to get away from the heat of Texas. More on this in the future.</li>\n</ul>\n<h2 id=\"till-next-year\" tabindex=\"-1\">Till next year<a class=\"c-anchor-link\" href=\"#till-next-year\" aria-label=\"permalink\" aria-describedby=\"till-next-year\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>That does it for my 2021.</p>\n<p>I’m curious to hear what you’re excited about in 2022. <a href=\"https://twitter.com/therealboone\">Let me know on Twitter</a>, and I’ll see you again next year!</p>\n",
      "date_published": "2021-12-28T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/kicking-sass-to-the-curb/",
      "url": "https://www.falldowngoboone.com/blog/kicking-sass-to-the-curb/",
      "title": "Kicking Sass to the curb",
      "content_html": "<p>Google web dev advocate and all-around awesome person <a href=\"https://twitter.com/Una/status/1375077749291896834?s=20\">Una Kravets mentioned in a tweet</a> earlier this year that got my wheels turning (I can hear them squeaking as I type):</p>\n<blockquote>\n<p>I used to write “Convert your CSS codebase into Sass!” guides\nNow I think it’s time for a “Convert your Sass codebase into vanilla CSS!” guide</p>\n</blockquote>\n<p>Sass is usually the first thing I install in a brand-new project, right after git and npm initialization. Could I bear to do without it now? And why would I want to get rid of Sass anyway?</p>\n<p>Simplicity is a worthy goal in any web dev endeavor, but maybe simplicity in the build chain is the most worthy goal of all. Removing a complete build branch makes the process easier to maintain and understand. But before I can even think about getting rid of Sass, I need to examine why I use it in the first place.</p>\n<h2 id=\"why-i-use-sass\" tabindex=\"-1\">Why I use Sass<a class=\"c-anchor-link\" href=\"#why-i-use-sass\" aria-label=\"permalink\" aria-describedby=\"why-i-use-sass\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I’ve used Sass in a variety of ways over the past decade, from Codekit to Gulp, WebPack, and most recently the JavaScript API (I also have experience with <a href=\"http://compass-style.org\">Compass</a>, although not by choice). <a href=\"https://sass-lang.com/documentation\">Sass offers several features</a>, but the ones I currently use are:</p>\n<ul>\n<li>Static variables</li>\n<li>Nesting</li>\n<li>Mixins</li>\n<li>Modules</li>\n</ul>\n<p>Let’s take a look at each one and see if vanilla CSS offers a suitable alternative.</p>\n<h2 id=\"static-variables\" tabindex=\"-1\">Static variables<a class=\"c-anchor-link\" href=\"#static-variables\" aria-label=\"permalink\" aria-describedby=\"static-variables\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I use Sass variables for storing colors, spacing values, font data, and breakpoints. They are one of the Sass features I lean on consistently. And now they’re easier to reason about thanks to <a href=\"https://sass-lang.com/documentation/at-rules/use\">the <code>@use</code> rule</a>.</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token comment\">// _colors.scss</span><br><span class=\"token property\"><span class=\"token variable\">$black</span></span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>10% 0 0<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token property\"><span class=\"token variable\">$red</span></span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>38% 68 33<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token comment\">// style.scss</span><br><span class=\"token keyword\">@use</span> <span class=\"token string\">\"colors\"</span> <span class=\"token module-modifier keyword\">as</span> c<span class=\"token punctuation\">;</span><br><br><span class=\"token selector\">.text </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">color</span><span class=\"token punctuation\">:</span> c.<span class=\"token variable\">$black</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// namespaced, which is useful for large Sass projects</span><br>  <br>  <span class=\"token selector\"><span class=\"token parent important\">&amp;</span>:hover </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">color</span><span class=\"token punctuation\">:</span> c.<span class=\"token variable\">$red</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The question is, <em>Can vanilla CSS replace my Sass variables?</em> This one seems easy at first. Variables, by way of <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties\">CSS custom properties</a>, have already made their way into many of my style sheets.</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token comment\">// root.css</span><br><br><span class=\"token selector\">:root </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">--black</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>10% 0 0<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--red</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>38% 68 33<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// style.css</span><br><br><span class=\"token selector\">.text </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--black<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <br>  <span class=\"token selector\"><span class=\"token parent important\">&amp;</span>:hover </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--red<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Sure, their syntax is weird at first, especially compared to Sass, but custom properties have superpowers Sass variables only wish they had. For starters, custom properties are dynamic and can change value based on the current context:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.container </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">--padding</span><span class=\"token punctuation\">:</span> 0.5rem<span class=\"token punctuation\">;</span><br><br>  <span class=\"token property\">padding</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--padding<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token atrule\"><span class=\"token rule\">@media</span> screen <span class=\"token operator\">and</span> <span class=\"token punctuation\">(</span><span class=\"token property\">min-width</span><span class=\"token punctuation\">:</span> 640px<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span><br>  <span class=\"token selector\">.container </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">--padding</span><span class=\"token punctuation\">:</span> 1rem<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Imagine changing the global spacing and typography by setting a couple of custom properties in the <code>:root</code> selector at different breakpoints. I’m heavily utilizing this pattern on this blog.</p>\n<p>Another nice thing about CSS custom properties is I can easily share and manipulate them with JavaScript. I talk more about this in my article about <a href=\"https://www.falldowngoboone.com/blog/share-variables-between-javascript-and-css/\">sharing variables between JavaScript and CSS</a>, but, in summary, custom properties are computed style, just like every other CSS property, so JavaScript can read and mutate them at will:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">:root </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">--my-property</span><span class=\"token punctuation\">:</span> hello<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">const</span> myProperty <span class=\"token operator\">=</span> <span class=\"token function\">getComputedStyle</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">.</span><span class=\"token function\">getPropertyValue</span><span class=\"token punctuation\">(</span><span class=\"token string\">'--my-property'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>myProperty<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// hello</span><br><br>document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">.</span>style<span class=\"token punctuation\">.</span><span class=\"token function\">setProperty</span><span class=\"token punctuation\">(</span><span class=\"token string\">'--my-property'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'goodbye'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> myMutatedProperty <span class=\"token operator\">=</span> <span class=\"token function\">getComputedStyle</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">.</span><span class=\"token function\">getPropertyValue</span><span class=\"token punctuation\">(</span><span class=\"token string\">'--my-property'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>myMutatedProperty<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// goodbye</span></code></pre>\n<p>The above example is scratching the surface of how CSS custom properties outshine their static Sass cousins, but I still haven’t dropped Sass variables altogether. There are a couple of areas where I yet prefer static variables.</p>\n<p>The CSS variables <a href=\"https://www.w3.org/TR/css-variables-1/#using-variables\">spec</a> states that the “<code>var()</code> function can not be used as property names, selectors, or anything else besides property values.” The property value rule is an unfortunate limitation on where and how custom properties are accessed.</p>\n<p>First, you can’t use custom properties as part of selectors, so no <code>&amp;__block</code> selectors. That’s not a deal-breaker for me since I’m moving away from doing that sort of thing in my code. Generating BEM selectors with the parent selector may not be terrible in a small, well-known codebase, but it becomes a nuisance when searching for selectors in larger codebases.</p>\n<p>The biggest bummer is you can’t use custom properties is in media queries. The first reason is <code>@-</code> rules are top-level, so there’s nowhere to set them and no way to inherit a value. Dynamic media query values can also create update cycles that never resolve (this could be why media queries created with <code>rem</code>s tended to be buggy early on as well).</p>\n<p>There is currently a proposal to add <a href=\"https://drafts.csswg.org/mediaqueries-5/#at-ruledef-custom-media\">custom media queries</a> that would solve this problem:</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token atrule\"><span class=\"token rule\">@custom-media</span> --md <span class=\"token punctuation\">(</span><span class=\"token property\">max-width</span><span class=\"token punctuation\">:</span> 30em<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span><br><br><span class=\"token atrule\"><span class=\"token rule\">@media</span> <span class=\"token punctuation\">(</span>--md<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span><br>  ...<br><span class=\"token punctuation\">}</span></code></pre>\n<p>It’s in Editor’s Draft at the time of this writing, but I’m hoping we’ll see it implemented soon.</p>\n<h3 id=\"static-variables-verdict\" tabindex=\"-1\">Static variables verdict<a class=\"c-anchor-link\" href=\"#static-variables-verdict\" aria-label=\"permalink\" aria-describedby=\"static-variables-verdict\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>I already use custom properties everywhere, and I predict custom media queries will one day replace my need for Sass’s static variables. For now, though, it seems Sass’s variables will continue to make my life easier.</p>\n<h2 id=\"nesting\" tabindex=\"-1\">Nesting<a class=\"c-anchor-link\" href=\"#nesting\" aria-label=\"permalink\" aria-describedby=\"nesting\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p><a href=\"https://sass-lang.com/documentation/style-rules#nesting\">Nesting</a> was the killer feature when I started using Sass. It was so convenient to nest rules inside of rules that I did it often. Probably too often. Now I limit myself to three levels of nesting, mostly pseudo-selectors and media queries.</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.button </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>57% 40 212<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">padding</span><span class=\"token punctuation\">:</span> 0.25em 0.5em<span class=\"token punctuation\">;</span><br><br>  <span class=\"token selector\">:hover </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>64% 40 212<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token selector\">:active </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>51% 40 212<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token selector\">::before </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">content</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"→\"</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token selector\">.uppercase-block <span class=\"token parent important\">&amp;</span> </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">text-transform</span><span class=\"token punctuation\">:</span> uppercase<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token atrule\"><span class=\"token rule\">@media</span> screen <span class=\"token operator\">and</span> <span class=\"token punctuation\">(</span><span class=\"token property\">min-width</span><span class=\"token punctuation\">:</span> 70em<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span><br>    <span class=\"token property\">padding</span><span class=\"token punctuation\">:</span> 0.5em<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The good news for camp vanilla CSS is there is a <a href=\"https://drafts.csswg.org/css-nesting-1/\">CSS Nesting Module proposal</a>. It’s slightly different from the Sass implementation. None of those fancy compound BEM-style ( e.g. <code>&amp;__element</code>) selectors and the nesting selector (<code>&amp;</code>) is always required, at least for now (Sass infers the current selector to be the first character unless explicitly used elsewhere in the selector).</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.button </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>57% 40 212<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">padding</span><span class=\"token punctuation\">:</span> 0.25em 0.5em<span class=\"token punctuation\">;</span><br><br>  <span class=\"token selector\"><span class=\"token parent important\">&amp;</span>:hover </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>64% 40 212<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token selector\"><span class=\"token parent important\">&amp;</span>:active </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">lch</span><span class=\"token punctuation\">(</span>51% 40 212<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token selector\"><span class=\"token parent important\">&amp;</span>::before </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">content</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"→\"</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token comment\">// hey, look, a new at-rule!</span><br>  <span class=\"token atrule\"><span class=\"token rule\">@nest</span> .uppercase-block &amp;</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token property\">text-transform</span><span class=\"token punctuation\">:</span> uppercase<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token atrule\"><span class=\"token rule\">@media</span> screen <span class=\"token operator\">and</span> <span class=\"token punctuation\">(</span><span class=\"token property\">min-width</span><span class=\"token punctuation\">:</span> 70em<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span><br>    <span class=\"token selector\"><span class=\"token parent important\">&amp;</span> </span><span class=\"token punctuation\">{</span><br>      <span class=\"token property\">padding</span><span class=\"token punctuation\">:</span> 0.5em<span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Unfortunately, the proposal is in Editor’s Draft as of this post’s publish date. But, hey, that’s also a good thing because at least the W3C is looking at it.</p>\n<h3 id=\"nesting-verdict\" tabindex=\"-1\">Nesting verdict<a class=\"c-anchor-link\" href=\"#nesting-verdict\" aria-label=\"permalink\" aria-describedby=\"nesting-verdict\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>I will gladly replace Sass nesting with native CSS nesting, provided it gets implemented. Even if I were to stay with Sass, chances are the Sass spec itself would have to change to support the new native CSS implementation.</p>\n<h2 id=\"mixins\" tabindex=\"-1\">Mixins<a class=\"c-anchor-link\" href=\"#mixins\" aria-label=\"permalink\" aria-describedby=\"mixins\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>There was a point when the main thing I would use mixins for was vendor prefixes, but Autoprefixer replaced them. Now that prefixes aren’t as prevalent, I manually add prefixes as needed.</p>\n<p>A current use I have for mixins, in combination with Sass variables, is creating custom media queries:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token comment\">// _utils.scss</span><br><br><span class=\"token property\"><span class=\"token variable\">$md-min</span></span><span class=\"token punctuation\">:</span> 611px<span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">@mixin</span> <span class=\"token function\">mq-max</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$width</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token atrule\"><span class=\"token rule\">@media</span> screen <span class=\"token operator\">and</span> <span class=\"token punctuation\">(</span><span class=\"token property\">max-width</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">$width</span><span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">@content</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">@mixin</span> <span class=\"token selector\">md-and-up </span><span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">@include</span> <span class=\"token function\">mq-min</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$md-min</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">@content</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// style.scss</span><br><br><span class=\"token keyword\">@use</span> <span class=\"token string\">\"./utils\"</span> <span class=\"token module-modifier keyword\">as</span> u<span class=\"token punctuation\">;</span><br><br><span class=\"token selector\">html </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">font-size</span><span class=\"token punctuation\">:</span> 112.5%<span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">@include</span> <span class=\"token selector\">u.md-and-up </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">font-size</span><span class=\"token punctuation\">:</span> 125%<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>I’ve already mentioned that native custom media queries are under consideration, so this use case is also covered (or, at least <em>will</em> be covered).</p>\n<p>I also dry up selector generation with mixins. Here is a sample mixin I’ve used in the past to generate utility classes:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token keyword\">@mixin</span> <span class=\"token function\">generateUtils</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$property-map</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$value-map</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$suffix</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">@each</span> <span class=\"token selector\"><span class=\"token variable\">$property-id</span>, <span class=\"token variable\">$properties</span> in <span class=\"token variable\">$property-map</span> </span><span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">@each</span> <span class=\"token selector\"><span class=\"token variable\">$value-id</span>, <span class=\"token variable\">$values</span> in <span class=\"token variable\">$value-map</span> </span><span class=\"token punctuation\">{</span><br>      <span class=\"token selector\">.u-<span class=\"token variable\">#{$property-id}</span>-<span class=\"token variable\">#{$value-id}</span><span class=\"token variable\">#{$suffix}</span> </span><span class=\"token punctuation\">{</span><br>        <span class=\"token keyword\">@each</span> <span class=\"token selector\"><span class=\"token variable\">$property</span> in <span class=\"token variable\">$properties</span> </span><span class=\"token punctuation\">{</span><br>          <span class=\"token property\"><span class=\"token variable\">#{$property}</span></span><span class=\"token punctuation\">:</span> <span class=\"token variable\">$values</span><span class=\"token punctuation\">;</span><br>        <span class=\"token punctuation\">}</span><br>      <span class=\"token punctuation\">}</span><br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>This admittedly opaque mixin loops through properties and values to create a bunch of utility classes. It’s a factory for margin and padding utility classes, similar to what you would find in Tailwind.</p>\n<p>There are several issues with the above utility factory. First of all, it creates a ton of classes, many of which may remain unused. We must then purge these classes with something like <a href=\"https://purgecss.com\">PurgeCSS</a>. This purging is further complicated by dynamically generated markup.</p>\n<p>The second issue is, as previously stated, this code is opaque. I can’t perform a simple global search to find a class created dynamically. I need <em>intimate</em> knowledge of the codebase to understand where the code generation occurs.</p>\n<p>Removing the factory and manually adding utility classes as you need them solves both problems:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.u-m-0 </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">margin</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--m-0<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token selector\">.u-m-1 </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">margin</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--m-1<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token selector\">.u-m-2 </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">margin</span><span class=\"token punctuation\">:</span> <span class=\"token function\">var</span><span class=\"token punctuation\">(</span>--m-2<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// ...etc.</span></code></pre>\n<p>It’s not perfect, but at least I can search for a utility class and find it. I can also add utilities as needed, which should prevent utility class bloat.</p>\n<p>The biggest drawback to this approach is you lose control over the abstraction. I’ve seen team members insert explicit values in the utility names (e.g. <code>u-m-15</code>, which would set the <code>margin</code> property to <code>15px</code>), which can, ironically, cause class bloat.</p>\n<p>Ultimately, I would prefer to avoid a utility-first solution, but if one is necessary, perhaps leaning on a library would be the best solution in this case. Tailwind has been improving leaps and bounds in reducing bloat, and it’s becoming a more familiar solution. Otherwise, it’s probably time to revisit your CSS methodology.</p>\n<h3 id=\"mixins-verdict\" tabindex=\"-1\">Mixins verdict<a class=\"c-anchor-link\" href=\"#mixins-verdict\" aria-label=\"permalink\" aria-describedby=\"mixins-verdict\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>There is no one-size-fits-all approach for replacing mixins. Determine why you or your team are using them and whether it makes sense to replace them. In short, It Depends™.</p>\n<h2 id=\"modules\" tabindex=\"-1\">Modules<a class=\"c-anchor-link\" href=\"#modules\" aria-label=\"permalink\" aria-describedby=\"modules\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Sass modules are an improvement over the old <code>@import</code> syntax. My main use for Sass modules is importing other stylesheets via the <code>@use</code> at-rule:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token comment\">// styles.scss</span><br><br><span class=\"token keyword\">@use</span> <span class=\"token string\">'reset'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">@use</span> <span class=\"token string\">'global'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">@use</span> <span class=\"token string\">'objects'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">@use</span> <span class=\"token string\">'components'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">@use</span> <span class=\"token string\">'utilities'</span><span class=\"token punctuation\">;</span></code></pre>\n<p><code>@use</code> allows me to split large style sheets up into manageable and composable chunks, which is one of the best use cases for Sass. Sass’s module system will only write a style sheet once, even if you import it multiple times.</p>\n<p>This module system is an instance where a build tool will always outshine a runtime approach. Sass will concatenate the imported files together and output a single file, which creates a larger style sheet but cuts down on HTTP requests. There are CSS alternatives (multiple <code>link</code> elements and the <code>@import</code> rule<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup>), but they involve separate HTTP requests.</p>\n<p>Of course, I assume that we still live in a world where fewer, larger HTTP requests are better than several small HTTP requests. HTTP/2 support is prevalent throughout modern browsers now, and many sites I have worked on have HTTP/2 turned on by default. I could forgo concatenating scripts, but I have yet to find a source that wholeheartedly recommends this approach (yet another attack of the It Depends monster).</p>\n<h3 id=\"modules-verdict\" tabindex=\"-1\">Modules verdict<a class=\"c-anchor-link\" href=\"#modules-verdict\" aria-label=\"permalink\" aria-describedby=\"modules-verdict\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>Honestly, this is such a new concept in Sass that I don’t see myself abandoning it any time soon. The power and simplicity of a statically-analyzed, build-time module system for CSS is a perfect use of Sass.</p>\n<h2 id=\"postcss\" tabindex=\"-1\">PostCSS<a class=\"c-anchor-link\" href=\"#postcss\" aria-label=\"permalink\" aria-describedby=\"postcss\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>A recurring theme throughout this article is certain CSS functionality has been proposed but is not yet available. One solution to this challenge that many of you are probably already thinking is to (🚨 obligatory marketing copy alert 🚨) <em>Use Tomorrow’s CSS Today</em> with <a href=\"https://preset-env.cssdb.org\">PostCSS Preset Env</a>.</p>\n<p>The Preset Env plugin is sort of like the CSS equivalent of Babel’s preset-env plugin. PostCSS Preset Env is prone to some of the same issues as Babel, namely code bloat and the risk of changing specifications breaking implementation, but it’s the best (only?) solution if you want to start using some of these future specs today. Available polyfills include the nesting and custom media query proposals mentioned earlier, as well as several others.</p>\n<p>Keep in mind, though, CSS affords much less flexibility than JavaScript when extending the language. That means polyfills may come with extreme limitations, like the Custom Property polyfill that only allows custom properties on the <code>:root</code> selector. Your mileage may vary.</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion<a class=\"c-anchor-link\" href=\"#conclusion\" aria-label=\"permalink\" aria-describedby=\"conclusion\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Will there ever be a time when I ditch Sass? I don’t know. Sass may continue evolving as CSS evolves, solving new problems we can’t even perceive at the moment.</p>\n<p>For now, though, Sass remains on my install list, even as I eye the inevitable list of goodies making their way through the CSS specification process. I’ve tried many times to move over to PostCSS, but I can never get it to stick. Sass is just easier to configure and use, at least for me.</p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>According to Harry Roberts, you should <a href=\"https://csswizardry.com/2018/11/css-and-network-performance/#avoid-import-in-css-files\">avoid the <code>@import</code> rule in CSS</a>. <code>@import</code> prevents a browser’s ability to download CSS in parallel and will slow down the initial render significantly. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-11-21T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/misadventures-in-web-components/",
      "url": "https://www.falldowngoboone.com/blog/misadventures-in-web-components/",
      "title": "Misadventures in web components",
      "content_html": "<p>I have been thinking about <a href=\"https://developer.mozilla.org/en-US/docs/Web/Web_Components\">web components</a> a lot lately, and I wanted to see how we could start using them at <a href=\"https://www.containerstore.com/welcome.htm\">The Container Store</a>. The idea was to pick a simple component and recreate it as a web component, and the first candidate that came to mind is our frequently-used quantity stepper. The stepper appears in several places throughout the website, and it’s dependent on an embarrassing amount of jQuery.</p>\n<p>Here’s my humble first attempt:</p>\n<p class=\"codepen\" data-height=\"450\" data-theme-id=\"dark\" data-default-tab=\"html,result\" data-user=\"falldowngoboone\" data-slug-hash=\"xxgMEax\" style=\"height: 450px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"Details\">\n  <span>See the Pen <a href=\"https://codepen.io/falldowngoboone/pen/xxgMEax\">\n  Details</a> by Ryan Boone (<a href=\"https://codepen.io/falldowngoboone\">@falldowngoboone</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>\n<p>The result isn’t perfect, but I gained a better understanding of web components, their limitations, and where they’re useful.</p>\n<h2 id=\"lessons-learned\" tabindex=\"-1\">Lessons learned<a class=\"c-anchor-link\" href=\"#lessons-learned\" aria-label=\"permalink\" aria-describedby=\"lessons-learned\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>My ultimate goal was to create a web component that progressively enhanced from a run-of-the-mill number input to a custom element. I also wanted to explore the limitations of web components inside a form. What I ended up with was this weird solution that sidesteps the shadow DOM altogether.</p>\n<h3 id=\"progressive-enhancement%E2%80%A6sort-of\" tabindex=\"-1\">Progressive enhancement…sort of<a class=\"c-anchor-link\" href=\"#progressive-enhancement%E2%80%A6sort-of\" aria-label=\"permalink\" aria-describedby=\"progressive-enhancement%E2%80%A6sort-of\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>The experimental component requires a donor number <code>input</code>, either as a child of <code>my-stepper</code> or, my preference, via a <code>data-is</code> attribute on a native <code>input[type=number]</code>. This is my naive version of <a href=\"https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#customized_built-in_elements\">customized built-ins</a>, which I suspect would be perfect for this particular situation.</p>\n<p>The reason for the hand-rolled functionality is because <a href=\"https://github.com/WICG/webcomponents/issues/509#issuecomment-230700060\">Safari doesn’t support customized built-ins</a>, nor do they intend to anytime soon<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup>. I will probably swap out my custom <code>data</code> attribute solution for a <a href=\"https://github.com/ungap/custom-elements\">polyfill that supports the native <code>is</code> attribute</a> when implementing in production because this is not implemented to spec.</p>\n<p>The <code>my-stepper</code>’s template inserts child content in between two <code>button</code>s wired up with click listeners. The listeners increment or decrement the value of the <code>input</code> (if present). The interesting thing about template <code>slot</code>s is their content remains in the light DOM, making them completely accessible to the parent form.</p>\n<p>The result ensures that the input remains an input if JavaScript is disabled or (more than likely) takes a while to load, parse and execute<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">[2]</a></sup>.</p>\n<h3 id=\"native-form-functionality\" tabindex=\"-1\">Native form functionality<a class=\"c-anchor-link\" href=\"#native-form-functionality\" aria-label=\"permalink\" aria-describedby=\"native-form-functionality\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>The shadow DOM encapsulates style and markup, but that comes at the cost of accessing field data in form field web components. Shadow DOM field values aren’t registered in <code>form.elements</code> and shadow fields cannot participate in the form lifecycle (e.g. field validation) by default.</p>\n<p>If you need to access field values, you can <a href=\"https://www.hjorthhansen.dev/shadow-dom-form-participation/\">use a hidden input</a> or <a href=\"https://web.dev/more-capable-form-controls/\">listen for the <code>formdata</code> event on the parent form</a>. Both strategies ensure you can pass data properly on submit, but neither will give you full access to the form lifecycle.</p>\n<p>The <a href=\"https://html.spec.whatwg.org/multipage/custom-elements.html#element-internals\"><code>ElementInternals</code></a> interface, however, officially grants web components access to the lifecycle of a parent form, including methods to determine the field’s value and validity:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">MyElement</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">HTMLElement</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>internals <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">attachInternals</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token comment\">// use internals to set the form field value, </span><br>    <span class=\"token comment\">// determine valid data, etc.</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>In addition to gaining access to the form lifecycle, the <code>ElementInternals</code> specification grants access to the <a href=\"https://html.spec.whatwg.org/multipage/custom-elements.html#accessibility-semantics\">accessibility object model</a>. <a href=\"https://caniuse.com/?search=attachinternals\">Only Chrome and Chromium-based browsers</a> support internals at the time of this writing, but, again, there are polyfills.</p>\n<h3 id=\"accessibility\" tabindex=\"-1\">Accessibility<a class=\"c-anchor-link\" href=\"#accessibility\" aria-label=\"permalink\" aria-describedby=\"accessibility\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>I learned that elements within the shadow DOM will still receive focus and are properly announced via a screen reader out-of-the-box (curiously, VoiceOver announces shadow DOM barriers as a new frame, at least at the time of this writing). I guess it acts sort of like an <code>iframe</code> in that respect?</p>\n<p>One concern I had, though, was how to reference an ID in the shadow DOM with a <code>label</code> in the light DOM. Unfortunately, shadow DOM ID reference is not possible, at least not natively. There have been discussions about somehow <a href=\"https://github.com/whatwg/html/issues/3219\">delegating labels via an option passed to <code>attachShadow</code></a>, but I haven’t seen anything regarding implementation.</p>\n<p>The only thing I found that works with the shadow DOM is determining the input’s label(s)<sup class=\"footnote-ref\"><a href=\"#fn3\" id=\"fnref3\">[3]</a></sup>, then adding click listeners to each that imperatively focus the shadow DOM target:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> template <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">'template'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>template<span class=\"token punctuation\">.</span>innerHTML <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"><br>&lt;input name=\"name\" /><br></span><span class=\"token template-punctuation string\">`</span></span><br><br><span class=\"token keyword\">class</span> <span class=\"token class-name\">MyInput</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">HTMLElement</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">static</span> <span class=\"token keyword\">get</span> <span class=\"token function\">formAssociated</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <br>  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">super</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">attachShadow</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">mode</span><span class=\"token operator\">:</span> <span class=\"token string\">'open'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>shadowRoot<span class=\"token punctuation\">.</span><span class=\"token function\">append</span><span class=\"token punctuation\">(</span>template<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">.</span><span class=\"token function\">cloneNode</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>internals <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>attachInternals<span class=\"token operator\">?.</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <br>  <span class=\"token function\">connectedCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>internals<span class=\"token punctuation\">.</span>labels<span class=\"token operator\">?.</span><span class=\"token function\">forEach</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">label</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>      console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>label<span class=\"token punctuation\">)</span><br>      label<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'click'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>shadowRoot<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'input'</span><span class=\"token punctuation\">)</span><span class=\"token operator\">?.</span><span class=\"token function\">focus</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br>customElements<span class=\"token punctuation\">.</span><span class=\"token function\">define</span><span class=\"token punctuation\">(</span><span class=\"token string\">'my-input'</span><span class=\"token punctuation\">,</span> MyInput<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Hey, check it out, we’re exercising the <code>ElementInternals</code> API! That didn’t take long.</p>\n<p>Note that we have to first specify that an element is form-associated with the <code>formAssociated</code> static property, then we can access the form-related internals. Also, note that we have to attach the click listeners in the <code>connectedCallback</code> method instead of the constructor (which is what I attempted at first)<sup class=\"footnote-ref\"><a href=\"#fn4\" id=\"fnref4\">[4]</a></sup>. Form association only happens after the element has attached to the DOM, so <code>this.internals.labels</code> is <code>null</code> in the constructor.</p>\n<h3 id=\"styling\" tabindex=\"-1\">Styling<a class=\"c-anchor-link\" href=\"#styling\" aria-label=\"permalink\" aria-describedby=\"styling\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>There are <a href=\"https://css-tricks.com/styling-web-components/\">several ways to customize web component styles</a>. For this experiment, I’m opening up custom styling via shadow parts and the <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/::part\"><code>::part()</code> CSS pseudo-element</a>. I think this strategy works for this particular instance since there are only three pieces that need to be styled: the two buttons and the wrapper.</p>\n<p>The <code>::part()</code> pseudo-element takes an identifier that is assigned with the <code>part</code> attribute:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">part</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>decrement control<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token entity named-entity\" title=\"&minus;\">&amp;minus;</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>slot</span><span class=\"token punctuation\">></span></span>CHILD CONTENT<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>slot</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">part</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>increment control<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>+<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span></code></pre>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token selector\">my-stepper::part(control)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">/* styles here */</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Note that you can pass multiple identifiers to <code>part</code>. I’m using this feature to allow consumers to style both buttons with the <code>control</code> shadow part and the individual buttons with their respective shadow parts.</p>\n<p>Shadow parts may not scale that well with more complex elements, and I haven’t tested how they would work on child web components (web components nested in a web component shadow DOM).</p>\n<h2 id=\"final-thoughts\" tabindex=\"-1\">Final thoughts<a class=\"c-anchor-link\" href=\"#final-thoughts\" aria-label=\"permalink\" aria-describedby=\"final-thoughts\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>As I mentioned earlier, I think the next step is to redo this component as a customized built-in and let a <a href=\"https://github.com/ungap/custom-elements\">polyfill</a> or library do all the heavy lifting. I’m curious to see what role, if any, shadow DOM plays in that particular type of web component.</p>\n<p>I’m also interested in exploring <a href=\"https://lit.dev\">LitElement</a> and <a href=\"https://stenciljs.com\">Stencil.js</a>, particularly how they would integrate with our current stack. My ultimate goal is to make web component creation as easy and gotcha-free as possible, and libraries help normalize some of the weirdness you may get with a low-level API like web components.</p>\n<p>I had a ton of fun messing around with web components, and I learned a lot as well. If you found this helpful or have something you’d like me to write about, let me know. I enjoy doing these experiments and hope to deep dive even more into web components in the future.</p>\n<p>Until next time!</p>\n<h2 id=\"resources\" tabindex=\"-1\">Resources<a class=\"c-anchor-link\" href=\"#resources\" aria-label=\"permalink\" aria-describedby=\"resources\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>More on web components and the accessibility object model: <a href=\"https://www.24a11y.com/2019/web-components-and-the-aom/\">https://www.24a11y.com/2019/web-components-and-the-aom/</a></li>\n<li>Best practices: <a href=\"https://developers.google.com/web/fundamentals/web-components/best-practices\">https://developers.google.com/web/fundamentals/web-components/best-practices</a></li>\n<li>Follow the latest in web components: <a href=\"https://www.webcomponents.org/\">https://www.webcomponents.org</a></li>\n<li>A nice overview of web component criticism: <a href=\"https://blog.logrocket.com/what-happened-to-web-components/\">https://blog.logrocket.com/what-happened-to-web-components/</a></li>\n</ul>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Safari engineers argue that customized built-ins violate the <a href=\"https://en.wikipedia.org/wiki/Liskov_substitution_principle\">Liskov substitution principle</a>. Given the fact that this custom stepper will only support an <code>input[type=number]</code>, I believe they’re probably right. But also, <code>HTMLInputeElement</code> is the element API equivalent of a dumpster fire. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>Yes, the site should just run faster, I agree. Baby steps. And in an ideal world, we would pre-render shadow DOM on the server and hydrate it client-side. Currently, shadow DOM is imperative-only, so there’s no way to render on the server, but there is a proposal for declarative shadow DOM, something I hope to write about soon. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn3\" class=\"footnote-item\"><p>Remember, labelable elements can have more than one label. <a href=\"#fnref3\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn4\" class=\"footnote-item\"><p>It’s a good idea to always run your side effects like attaching listeners inside <code>connectedCallback</code>, even if you have access in the constructor. And make sure you clean up any listeners in the <code>disconnectedCallback</code> method. See the resources section for a link to web component best practices. <a href=\"#fnref4\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-05-16T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/pardon-the-dust/",
      "url": "https://www.falldowngoboone.com/blog/pardon-the-dust/",
      "title": "Pardon the dust",
      "content_html": "<p>In case you didn’t notice, I just pushed up the biggest adjustment to the site design since the <a href=\"https://www.falldowngoboone.com/blog/how-im-redesigning-my-blog/\">last redesign</a> in late 2020. I wanted to go through it briefly and talk about what’s next.</p>\n<p>From the moment I published the last redesign, I’ve been working on improvements to the post template. The old posts felt blocky and sterile, and I wasn’t happy with the overall reading experience on smaller devices.</p>\n<p>For design exploration I turned once again to Figma, relying heavily on the Figma Mirror app on my iPhone and iPad Air. My design goals were to improve post readability and inject some personality into the site.</p>\n<h2 id=\"typography-updates\" tabindex=\"-1\">Typography updates<a class=\"c-anchor-link\" href=\"#typography-updates\" aria-label=\"permalink\" aria-describedby=\"typography-updates\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The previous body copy was a <a href=\"https://css-tricks.com/snippets/css/system-font-stack/\">system font stack</a>, which I think is great for applications, but for a personal blog, I wanted something slightly more unique. I added my former heading font <a href=\"https://www.myfonts.com/fonts/tipotype/rotunda/\">Rotunda</a> to the stack. Rotunda was supposed to be the body copy from the start (it’s all over my old Figma comps), but I never switched it over on the site until now.</p>\n<p>Next, I wanted to replace Rotunda as my heading font with something warm and retro. <a href=\"https://www.myfonts.com/fonts/latinotype/recoleta/\">Recoleta Black</a> fills the role nicely with soft serifs, tall x-height, and tons of stroke contrast. It’s a great counterpoint to the crispness of Rotunda.</p>\n<p><img src=\"my-fonts.png\" alt=\"A look at my fonts\"></p>\n<p>Something I’m trying out that I’ve avoided for quite some time is using units in my line heights. For as long as I can remember I’ve avoided units in line height because of the way line-height is inherited. Using a unit, even if it’s a relative unit, forces the calculated value at the point of assignment to be the line-height of all children.</p>\n<p>So why am I using units now? Since unit-less line-height depends on the font size of the box it’s assigned to, it was becoming increasingly difficult to maintain a somewhat consistent vertical rhythm. I’m also tying specific line-heights to specific font sizes, so they act like presets now, which makes them easier to track and apply.</p>\n<p>This switch was partly inspired by Dan Mall’s <a href=\"https://superfriendlydesign.systems/articles/typography-in-design-systems/\">Typography in Design Systems</a> article, which I heavily recommend (actually, I heavily recommend anything written by Dan). In the article, Dan talks about the utility of creating presets, something that I intend on doing once I have some breathing room.</p>\n<h2 id=\"the-logo\" tabindex=\"-1\">The logo<a class=\"c-anchor-link\" href=\"#the-logo\" aria-label=\"permalink\" aria-describedby=\"the-logo\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Hey, I’ve got a new logo! The old logo was a quick scribble in Affinity Designer. The new logo features <a href=\"https://www.myfonts.com/fonts/hurufatfont-type-foundry/masifa-rounded/\">Masifa Rounded</a>, another soft, friendly font (I’m starting to detect a theme here). I feel like in thicker weights it starts to feel like it’s been run through an old copier, which I appreciate.</p>\n<p><img src=\"my-logos.png\" alt=\"The regular and compact versions of my logo\"></p>\n<p>The plan is to eventually add some fun, hand-drawn logo animations that load randomly. I think that’ll be a nice way to add a bit more discovery to the site.</p>\n<h2 id=\"more-hand-drawn-elements\" tabindex=\"-1\">More hand-drawn elements<a class=\"c-anchor-link\" href=\"#more-hand-drawn-elements\" aria-label=\"permalink\" aria-describedby=\"more-hand-drawn-elements\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>My original plan was to include more sketched elements from the very beginning, and now I’m starting to follow through with that with the new divider. I have plans to add additional sketch elements throughout.</p>\n<p>For now, I’m sketching directly in Figma for a mono-line feel. Soon I’ll be getting a new iPad Pro and Apple Pencil, so I’m curious to see what I can do with that setup.</p>\n<h2 id=\"github-projects\" tabindex=\"-1\">GitHub Projects<a class=\"c-anchor-link\" href=\"#github-projects\" aria-label=\"permalink\" aria-describedby=\"github-projects\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>One administrative change is I’m managing the project in <a href=\"https://github.com/features/project-management/\">GitHub Projects</a>. I like keeping everything in a single place, and I’ve been curious about GitHub Projects for a while.</p>\n<p>So far it’s been straightforward. I like how I can automate the creation of cards by simply assigning a pull request or issue to my project. I’m using GitHub projects to track my bugs as well.</p>\n<h2 id=\"what%E2%80%99s-next\" tabindex=\"-1\">What’s next<a class=\"c-anchor-link\" href=\"#what%E2%80%99s-next\" aria-label=\"permalink\" aria-describedby=\"what%E2%80%99s-next\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The work is never done, and I’m still focused on finishing out my post template. After that, I have the home page in my sights.</p>\n<p>I’d love to look into <a href=\"https://www.11ty.dev/docs/plugins/image/\"><code>eleventy-img</code></a> for improved image performance. I also need to enable heading links for deep linking. That should only take a couple of minutes.</p>\n<p>Finally, I have a desire to explore Web Components. In a recent article, <a href=\"https://www.joshwcomeau.com/blog/how-i-built-my-blog/\">Josh W. Comeau dives into how he built his blog</a>, and he talks at length about how he uses React and MDX to create his one-off, interactive examples. I would love to do something similar with Web Components and Markdown.</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion<a class=\"c-anchor-link\" href=\"#conclusion\" aria-label=\"permalink\" aria-describedby=\"conclusion\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I hope you enjoyed this quick look at the latest adjustments to my blog. I have a lot of fun working on it, especially being able to revisit my design and illustrative roots. Are you in the middle of a blog redesign? <a href=\"https://twitter.com/therealboone\">I’d love to hear from you</a> about how it’s going.</p>\n<p>That’s it for now. I’ll be returning to my regularly scheduled blog posts next month. Catch you then!</p>\n",
      "date_published": "2021-04-30T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/the-curious-case-of-flexbox-gap-and-safari/",
      "url": "https://www.falldowngoboone.com/blog/the-curious-case-of-flexbox-gap-and-safari/",
      "title": "The curious case of flexbox gap and Safari",
      "content_html": "<p><strong>Update at the end</strong></p>\n<p>The <code>gap</code> property was first introduced to add inner grid spacing but was extended in the spec to work with flexbox. With one line of code, you can replace something like this:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.flex-container </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">display</span><span class=\"token punctuation\">:</span> flex<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">flex-wrap</span><span class=\"token punctuation\">:</span> wrap<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">align-items</span><span class=\"token punctuation\">:</span> center<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">margin</span><span class=\"token punctuation\">:</span> -0.5em<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><span class=\"token selector\">.flex-container > * </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">margin</span><span class=\"token punctuation\">:</span> 0.5em<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>with this:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.flex-container </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">display</span><span class=\"token punctuation\">:</span> flex<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">flex-wrap</span><span class=\"token punctuation\">:</span> wrap<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">align-items</span><span class=\"token punctuation\">:</span> center<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">gap</span><span class=\"token punctuation\">:</span> 1em<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>That’s nice, but Safari doesn’t support <code>gap</code> in flexbox just yet. Normally I’d just reach for <code>@supports</code>:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.flex-container </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">display</span><span class=\"token punctuation\">:</span> flex<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">flex-wrap</span><span class=\"token punctuation\">:</span> wrap<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">align-items</span><span class=\"token punctuation\">:</span> center<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">gap</span><span class=\"token punctuation\">:</span> 1em<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token atrule\"><span class=\"token rule\">@supports</span> <span class=\"token operator\">not</span> <span class=\"token punctuation\">(</span><span class=\"token property\">gap</span><span class=\"token punctuation\">:</span> 1em<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span><br>  <span class=\"token selector\">.flex-container </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">margin</span><span class=\"token punctuation\">:</span> -0.5em<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <span class=\"token selector\">.flex-container > * </span><span class=\"token punctuation\">{</span><br>    <span class=\"token property\">margin</span><span class=\"token punctuation\">:</span> 0.5em<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Unfortunately, <a href=\"https://caniuse.com/mdn-css_properties_gap_grid_context\">Safari already supports <code>gap</code> in grid</a>, so this doesn’t work. This is one of those weird cases where there is no easy CSS-only solution, though there have been <a href=\"https://github.com/w3c/csswg-drafts/issues/3559\">proposals for workarounds</a>.</p>\n<p>This has left me scratching my head. You could <a href=\"https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/flexgap.js\">polyfill with JavaScript</a> or <a href=\"https://github.com/nkt/postcss-flexboxgrid\">use PostCSS</a>, but at this point, is it worth it? That’s a question that all frontend developers have to weigh from time to time, and there’s no one-size-fits-all answer.</p>\n<p>I will probably wait until Safari supports flexbox gap in the latest two versions before using it, mainly because it doesn’t take that much more CSS to achieve the same effect. The only drawback is I cannot change the margins of the flex container. This can be overcome with an extra wrapper element, but then you’re starting to complicate the markup.</p>\n<p>If you want to read more about the flexbox gap issue, <a href=\"https://ishadeed.com/article/flexbox-gap/\">check out this post from Ahmad Shadeed</a>. And if you found this post helpful, please like it on Dev Community and <a href=\"https://twitter.com/therealboone\">let me know on Twitter</a>.</p>\n<p>Until tomorrow!</p>\n<h2 id=\"update\" tabindex=\"-1\">Update<a class=\"c-anchor-link\" href=\"#update\" aria-label=\"permalink\" aria-describedby=\"update\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>As of Safari 14.1, <a href=\"https://caniuse.com/?search=gap\">flex gap is now supported</a>! This brings me one step closer to replacing my object styles that do the same thing. I typically wait until something is supported in the last two versions of the evergreen browsers (or can be worked around).</p>\n<p>I would still love to have a way to use <code>@supports</code>, but I’ll take what I can get. Anyway, happy coding!</p>\n",
      "date_published": "2021-04-28T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/baking-in-syntax-highlighting/",
      "url": "https://www.falldowngoboone.com/blog/baking-in-syntax-highlighting/",
      "title": "Baking in syntax highlighting",
      "content_html": "<p>Another runtime dependency bites the dust. My ongoing work of <a href=\"https://www.falldowngoboone.com/blog/how-im-redesigning-my-blog/\">designing and building this blog</a> continues with moving syntax highlighting from the client-side to <a href=\"https://www.11ty.dev/docs/plugins/syntaxhighlight/\">Eleventy’s syntax highlighting plugin</a>:</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> syntaxHighlighting <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'@11ty/eleventy-plugin-syntaxhighlight'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">eleventyConfig</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addPlugin</span><span class=\"token punctuation\">(</span>syntaxHighlighting<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token comment\">// other config stuff...</span><br><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token literal-property property\">dir</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token literal-property property\">input</span><span class=\"token operator\">:</span> <span class=\"token string\">'src'</span><span class=\"token punctuation\">,</span><br>      <span class=\"token literal-property property\">layouts</span><span class=\"token operator\">:</span> <span class=\"token string\">'_includes/layouts'</span><span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>There are a couple of benefits to baking syntax highlighting into the build process vs. runtime. First of all, there’s no flash of unstyled markup in cases where JavaScript is slow to parse. Second, JavaScript is no longer required for syntax highlighting.</p>\n<p>There are issues, of course. One of my goals is to add line numbers to code blocks, and while there is a <a href=\"https://prismjs.com/plugins/line-numbers/\">Prism line number plugin</a>, it requires DOM to be present. Since there is no DOM during the plugin phase of Eleventy, this plugin doesn’t work.</p>\n<p>After searching around a bit, I found a <a href=\"https://github.com/11ty/eleventy-plugin-syntaxhighlight/issues/10\">clever trick involving CSS counters</a> (thanks to Josh Buchea), but it breaks under certain conditions due to an issue with the line highlighting plugin. I detailed a few of the conditions in an <a href=\"https://github.com/falldowngoboone/falldowngoboone-com/issues/116\">issue I filed on my site</a>.</p>\n<p>It looks like there is a possible fix that’s been opened, but I don’t see any activity around the pull request. It may be worth it to pull the commit into a third-party plugin, but that’s an exercise for later.</p>\n<p>There have been other changes since last I posted about the blog, but nothing too drastic. Now that I’ve got some more time on my hands, I hope to knock out some changes I’ve prioritized and make this a proper frontend playground.</p>\n<p>Till next time!</p>\n",
      "date_published": "2021-04-01T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/native-form-validation-with-javascript/",
      "url": "https://www.falldowngoboone.com/blog/native-form-validation-with-javascript/",
      "title": "Native form validation with JavaScript",
      "content_html": "<p>You don’t need to install a validation library to create rich client-side form validation experiences. HTML5’s native client-side form validation is widely-supported and easy to implement, and while its default functionality is limited, the native <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Constraint_validation\">Constraint Validation API</a> allows for custom behavior with JavaScript.</p>\n<h2 id=\"enter-the-humble-login-form\" tabindex=\"-1\">Enter the humble login form<a class=\"c-anchor-link\" href=\"#enter-the-humble-login-form\" aria-label=\"permalink\" aria-describedby=\"enter-the-humble-login-form\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Let’s build a login form. We’ll use an input for email, password, and a submit button:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- login.html --></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>form</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>login-form<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">action</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/api/auth<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">method</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>post<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Your Email<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Your Password<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span><span class=\"token punctuation\">></span></span>Log In<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>form</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>That’s a pretty bare-bones login form. There are two inputs, one with a type of <code>email</code>, the other with a type of <code>password</code>, and a submit button. The form posts to an endpoint that handles the login process on the server<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup>.</p>\n<p>Even though we haven’t yet done anything to the form, it already has some client-side validation built in, thanks to the <code>email</code> input. If you were to enter an invalid value into the email field and submit, you would see something like this (screenshot from Chrome):</p>\n<p><img src=\"screen-shot-1.png\" alt=\"Chrome invalid email error, Please include an '@' in the email address\"></p>\n<p>The browser has blocked the submission of data, focused the first invalid field, and now we see an error message describing the issue. We have email validation, and at no point did we type <code>npm install</code> and download half of all known JavaScript dependencies.</p>\n<p>There is a problem, though. If you submit with both fields left blank, the form submits as valid, but our backend script requires both fields.</p>\n<h2 id=\"requiring-fields\" tabindex=\"-1\">Requiring fields<a class=\"c-anchor-link\" href=\"#requiring-fields\" aria-label=\"permalink\" aria-describedby=\"requiring-fields\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>There’s an easy fix for the valid blank fields. Let’s add the <code>required</code> attribute to both the email and password inputs.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- login.html --></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>form</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>login-form<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">action</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/api/auth<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">method</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>post<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Your Email<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>br</span><span class=\"token punctuation\">/></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">required</span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Your Password<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>br</span><span class=\"token punctuation\">/></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">required</span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span><span class=\"token punctuation\">></span></span>Log In<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>form</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Now submitting without an email or password will look something like this (again, screenshot from Chrome):</p>\n<p><img src=\"screen-shot-2.png\" alt=\"Chrome missing value error, Please fill out this field\"></p>\n<p>So far, so good. Who needs JavaScript?</p>\n<h2 id=\"styling-error-state\" tabindex=\"-1\">Styling error state<a class=\"c-anchor-link\" href=\"#styling-error-state\" aria-label=\"permalink\" aria-describedby=\"styling-error-state\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>You might want to style your error state to draw more attention to fields with issues. We can do that by using the <code>:invalid</code> CSS pseudo-class.</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token comment\">/* login.css */</span><br><br><span class=\"token selector\">input:invalid</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token property\">border-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">hsl</span><span class=\"token punctuation\">(</span>351<span class=\"token punctuation\">,</span> 100%<span class=\"token punctuation\">,</span> 27%<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Now we see the first issue: HTML forms run validation immediately. By default, both the email and password fields are blank, and since they are required, they immediately render invalid. Boo!</p>\n<p>Ideally, we would want the fields to appear valid until a user attempts to enter a value. We could choose either to validate on blur or wait until the user tries to submit the form. Either way, we want to validate invalidated fields as their values update to ensure the quickest feedback possible.</p>\n<p>Sadly, we have reached the limits of default HTML client-side form validation. But fear not! We have access in JavaScript to all that validation goodness in the form of the aforementioned Constraint Validation API.</p>\n<h2 id=\"validation%2C-final-form\" tabindex=\"-1\">Validation, final form<a class=\"c-anchor-link\" href=\"#validation%2C-final-form\" aria-label=\"permalink\" aria-describedby=\"validation%2C-final-form\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The Constraint Validation API gives you complete access to the built-in validation we’ve been using up to this point but with more control. The first rule of Constraint Validation, much like Fight Club, is to not talk about validation:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// login-validate.js</span><br><br><span class=\"token keyword\">const</span> form <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"login-form\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>form<span class=\"token punctuation\">.</span>noValidate <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Setting <code>noValidate</code> turns off the native client-side validation, freeing us up to do whatever we want. Turning off validation with JavaScript ensures the default validation still runs if JavaScript never executes for whatever reason. It also prevents showing our invalid style preemptively.</p>\n<p>The first thing we should do is run validation when the form is submitted. To validate the entire form, use the form method <code>reportValidity</code>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// login-validate.js</span><br><br><span class=\"token keyword\">const</span> form <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"login-form\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>form<span class=\"token punctuation\">.</span>noValidate <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span><br><br>form<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'submit'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleFormSubmit</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> isValid <span class=\"token operator\">=</span> form<span class=\"token punctuation\">.</span><span class=\"token function\">reportValidity</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>isValid<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token comment\">// POST form data to backend with fetch</span><br>  <span class=\"token punctuation\">}</span><br><br>  event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p><code>reportValidity</code> runs the form validation, returns <code>true</code> or <code>false</code> based on whether or not the form is valid, and reports any validation errors to the user. We can use the return value to determine whether or not to post to the backend.</p>\n<h2 id=\"marking-invalid-inputs\" tabindex=\"-1\">Marking invalid inputs<a class=\"c-anchor-link\" href=\"#marking-invalid-inputs\" aria-label=\"permalink\" aria-describedby=\"marking-invalid-inputs\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Before taking the validation reins we could tie into the convenient <code>:invalid</code> pseudo-class to style invalid fields, but now that’s no longer an option. Let’s fix that next.</p>\n<p>When <code>reportValidity</code> runs, it will dispatch an <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/invalid_event\"><code>invalid</code></a> event for each invalid field. This event is cancellable, but it doesn’t bubble, which means we’ll have to register an event handler on each element in the form:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// login-validate.js</span><br><br><span class=\"token comment\">// ...</span><br><br><span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> field <span class=\"token keyword\">of</span> form<span class=\"token punctuation\">.</span>elements<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleInvalidField</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">setAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>This will add the <code>aria-invalid</code> attribute to invalid elements, which not only communicates validity state to accessible technology, it gives us a new hook for our invalid styles<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">[2]</a></sup>.</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token comment\">/* login.css */</span><br><br><span class=\"token selector\">input:invalid,<br>[aria-invalid=true]</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token property\">border-color</span><span class=\"token punctuation\">:</span> <span class=\"token function\">hsl</span><span class=\"token punctuation\">(</span>351<span class=\"token punctuation\">,</span> 100%<span class=\"token punctuation\">,</span> 27%<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Whenever I can, I try to tie style to semantics. This helps communicate the importance of the selector’s existence and avoids unnecessary styles that may not be that reusable outside of the current context.</p>\n<p>The styles work now, but they remain even after the input becomes valid. Before we can correct that, there’s another problem we need to solve.</p>\n<h2 id=\"our-new-validation-pattern\" tabindex=\"-1\">Our new validation pattern<a class=\"c-anchor-link\" href=\"#our-new-validation-pattern\" aria-label=\"permalink\" aria-describedby=\"our-new-validation-pattern\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>We need to talk briefly about how we want this custom validation to work. Luckily for us, form error UX is well-researched. For this example, I’m referring to <a href=\"https://www.nngroup.com/articles/errors-forms-design-guidelines/\">guidelines published by the Nielsen Norman Group</a>.</p>\n<p>Here’s a quick summary of the plan:</p>\n<ul>\n<li>Each field will first validate on the <code>blur</code> event. This will avoid displaying warnings too early.</li>\n<li>Once a field has been visited initially, it will validate on user input. Immediate feedback helps users verify the information they’ve entered is correct. This also addresses the invalid style issue we currently have.</li>\n<li>Errors will be displayed alongside the field. We’ll replace the default error tooltips with inline messages that remain on screen as long as the field is invalid.</li>\n</ul>\n<p>First I’ll add the validation on field blur. We’ll add that to our previous field level JavaScript:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// login-validate.js</span><br><br><span class=\"token comment\">// ...</span><br><br><span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> field <span class=\"token keyword\">of</span> form<span class=\"token punctuation\">.</span>elements<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">// previous code</span><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleInvalidField</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">setAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token comment\">// new</span><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"blur\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleFieldBlur</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">checkValidity</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>When a field element dispatches a <code>blur</code> event, we optimistically remove the <code>aria-invalid</code> attribute and then run <code>checkValidity</code>, which does everything <code>reportValidity</code> does except report validation errors to the user. We’ll handle error reporting ourselves later.</p>\n<p>Next, we need to run validation on user input, but only after a field has been previously visited. For that, we’ll need some local state.</p>\n<h2 id=\"validating-on-user-input\" tabindex=\"-1\">Validating on user input<a class=\"c-anchor-link\" href=\"#validating-on-user-input\" aria-label=\"permalink\" aria-describedby=\"validating-on-user-input\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>For tracking fields that have been visited, we’ll use a simple JavaScript array. Once a field has been visited, we’ll push it into the array. To check for visited status, we query the array to see if the field is included.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// login-validate.js</span><br><br><span class=\"token comment\">// ...</span><br><br><span class=\"token comment\">// new</span><br><span class=\"token keyword\">const</span> visited <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br><br><span class=\"token comment\">// ...</span><br><br><span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> field <span class=\"token keyword\">of</span> form<span class=\"token punctuation\">.</span>elements<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">// ...</span><br><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"blur\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleFieldBlur</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token comment\">// new</span><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>visited<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      visited<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br><br>    <span class=\"token comment\">// REMOVED field.removeAttribute(\"aria-invalid\");</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">checkValidity</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token comment\">// new</span><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"input\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleFieldInput</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>visited<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span><br>  <br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>field<span class=\"token punctuation\">.</span>validity<span class=\"token punctuation\">.</span>valid<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      field<span class=\"token punctuation\">.</span><span class=\"token function\">setAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span><br>      field<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Here we have added a <code>visited</code> array and are adding fields to it inside <code>handleFieldBlur</code>. We’re also removing the <code>aria-invalid</code> attribute code since it’s now handled in the new input handler.</p>\n<p>Inside the input handler, we prevent validation from running before the field has been visited with a short circuit. We check the field’s validity using its <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/ValidityState\"><code>ValidityState</code></a>, which is a handy object that contains everything related to field validation. More on that in a bit.</p>\n<p>At this point, the desired validation behavior is done. The final thing we need to do is add custom error styling.</p>\n<h2 id=\"custom-inline-errors\" tabindex=\"-1\">Custom inline errors<a class=\"c-anchor-link\" href=\"#custom-inline-errors\" aria-label=\"permalink\" aria-describedby=\"custom-inline-errors\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The current error messages only show up on a submission attempt and have the default tooltip styling. We want to show the errors directly underneath the invalid fields and update them on blur and user input. We need to first create containers for the error messages.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- login.html --></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>form</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>login-form<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">action</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/api/auth<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">method</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>post<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Your Email<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <br>          <span class=\"token attr-name\">aria-describedby</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email-error<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span> <span class=\"token comment\">&lt;!-- new --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email-error<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span> <span class=\"token comment\">&lt;!-- new --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Your Password<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password<span class=\"token punctuation\">\"</span></span> <br>          <span class=\"token attr-name\">aria-describedby</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password-error<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span> <span class=\"token comment\">&lt;!-- new --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>password-error<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span> <span class=\"token comment\">&lt;!-- new --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span><span class=\"token punctuation\">></span></span>Log In<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>form</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>The important thing to notice in the above markup is we’ve added an <code>aria-describedby</code> attribute to both inputs. This attribute ensures that screen readers associate each error message with its respective input. When an invalid input is focused, the screen reader will announce the input’s label and type, pause briefly, then announce the error<sup class=\"footnote-ref\"><a href=\"#fn3\" id=\"fnref3\">[3]</a></sup>.</p>\n<p>We now need to populate the error containers with the appropriate error messages. Luckily the input fields have access to their validation messages:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// login-validate.js</span><br><br><span class=\"token comment\">// ...</span><br><br><span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> field <span class=\"token keyword\">of</span> form<span class=\"token punctuation\">.</span>elements<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleInvalidField</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">errorContainer</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>textContent <span class=\"token operator\">=</span> field<span class=\"token punctuation\">.</span>validationMessage<span class=\"token punctuation\">;</span> <span class=\"token comment\">// new</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">setAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// new, prevents default validation errors</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token comment\">// ...</span><br><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"input\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleFieldInput</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>visited<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span><br>  <br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>field<span class=\"token punctuation\">.</span>validity<span class=\"token punctuation\">.</span>valid<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token function\">errorContainer</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>textContent <span class=\"token operator\">=</span> field<span class=\"token punctuation\">.</span>validationMessage<span class=\"token punctuation\">;</span> <span class=\"token comment\">// new</span><br>      field<span class=\"token punctuation\">.</span><span class=\"token function\">setAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token function\">errorContainer</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>textContent <span class=\"token operator\">=</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// new</span><br>      field<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// new</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">errorContainer</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">field</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> errorContainerId <span class=\"token operator\">=</span> field<br>    <span class=\"token punctuation\">.</span><span class=\"token function\">getAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-describedby\"</span><span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">.</span><span class=\"token function\">split</span><span class=\"token punctuation\">(</span><span class=\"token string\">\" \"</span><span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> id<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">return</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span>errorContainerId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Before we go any further, it looks like every time we set the error container text, we also set the <code>aria-invalid</code> attribute on the field. Let’s clean this logic up by moving it into a function.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// login-validate.js</span><br><br><span class=\"token comment\">// ...</span><br><br><span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> field <span class=\"token keyword\">of</span> form<span class=\"token punctuation\">.</span>elements<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleInvalidField</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">setFieldValidity</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// function-ified</span><br>    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token comment\">// ...</span><br><br>  field<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"input\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleFieldInput</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>visited<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span><br>    <span class=\"token function\">setFieldValidity</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// here too</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// ...</span><br><br><span class=\"token comment\">// new</span><br><span class=\"token keyword\">function</span> <span class=\"token function\">setFieldValidity</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">field</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>field<span class=\"token punctuation\">.</span>validity<span class=\"token punctuation\">.</span>valid<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">errorContainer</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>textContent <span class=\"token operator\">=</span> field<span class=\"token punctuation\">.</span>validationMessage<span class=\"token punctuation\">;</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">setAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">errorContainer</span><span class=\"token punctuation\">(</span>field<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>textContent <span class=\"token operator\">=</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">;</span><br>    field<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttribute</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-invalid\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Here’s what our custom errors look like now when we try to submit with blank inputs (I’m adding the red “X” with CSS):</p>\n<p><img src=\"screen-shot-3.png\" alt=\"Custom form errors underneath email and password inputs\"></p>\n<h2 id=\"better-form-validation\" tabindex=\"-1\">Better form validation<a class=\"c-anchor-link\" href=\"#better-form-validation\" aria-label=\"permalink\" aria-describedby=\"better-form-validation\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>At this point, there are some rough edges, but it’s working more or less as we want it to. One annoying thing is in Chrome validation messages get wordy. You can substitute a custom validation message based on the type of validation error is associated with the field. I’ll leave that as an exercise for you.</p>\n<p>This exploration only looked at required fields and email pattern validation, but there are a variety of validation criteria built into browser validation. Like the <code>email</code> input type, there are several other <a href=\"https://developer.mozilla.org/en-US/docs/Learn/Forms/HTML5_input_types\">input types</a> with built-in validation, as well as ways to limit the range or length of an input’s value, and a <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern\">pattern attribute</a> that gives you even more control over input validation for certain types of inputs.</p>\n<h2 id=\"keep-exploring\" tabindex=\"-1\">Keep exploring<a class=\"c-anchor-link\" href=\"#keep-exploring\" aria-label=\"permalink\" aria-describedby=\"keep-exploring\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I hope this post has inspired you to explore the Constraint Validation API. Taking advantage of native APIs improves frontend performance and moves complex logic off of your plate. Use them whenever possible.</p>\n<p>Do you like Web APIs? What’s your favorite? Which one mystifies you? Let me know on DEV Community or Twitter. And if you enjoyed this post, let me know by liking it on DEV Community and giving me a follow.</p>\n<p>Until next time, keep exploring!</p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Our imaginary backend script also validates and sanitizes the data posted from the form. Client-side validation is a user experience enhancement. Never trust user-generated data and always validate on the server. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>To learn more about ARIA attributes, roles, and relationships, check out the <a href=\"https://www.w3.org/TR/2021/CR-wai-aria-1.2-20210302/\">WAI-ARIA specification</a>. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn3\" class=\"footnote-item\"><p><code>aria-describedby</code> can take multiple IDs separated by spaces (<code>aria-described=&quot;first-id second-id third-id&quot;</code>). This is helpful if you have instructions associated with an input, like password constraints. <a href=\"#fnref3\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-03-27T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/hold-off-on-optimizing-javascript-performance/",
      "url": "https://www.falldowngoboone.com/blog/hold-off-on-optimizing-javascript-performance/",
      "title": "Hold off on optimizing JavaScript performance",
      "content_html": "<p>As a developer, I love optimizing performance. Learning efficient algorithms makes me <em>feel</em> like a software engineer. But performance is not the only developer concern, nor should it be the first or second. <a href=\"https://twitter.com/DavidKPiano/status/1367855571077128196?s=20\">David K. Piano recently pointed this out on Twitter</a>, offering up a suggested framework:</p>\n<blockquote>\n<p>Make it work<br/>\nMake it always work<br/>\nMake it work for everyone<br/>\nMake it right<br/>\nMake it fast</p>\n</blockquote>\n<p>David’s suggestion expands on a well-known <a href=\"https://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast\">programming maxim attributed to Kent Beck</a>, <em>Make it work, Make it right, Make it fast</em>. What does that mean? I want to take some time to expand on each layer.</p>\n<h2 id=\"make-it-work\" tabindex=\"-1\">Make it work<a class=\"c-anchor-link\" href=\"#make-it-work\" aria-label=\"permalink\" aria-describedby=\"make-it-work\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Making working code is the first concern. This step may seem obvious, but there are a few things to consider as you make the code work.</p>\n<p>First, consider a <a href=\"https://www.agilealliance.org/glossary/tdd/#q=~(infinite~false~filters~(postType~(~'page~'post~'aa_book~'aa_event_session~'aa_experience_report~'aa_glossary~'aa_research_paper~'aa_video)~tags~(~'tdd))~searchTerm~'~sort~false~sortDirection~'asc~page~1)\">test-driven development</a> approach. At the very least, wrap your code in tests as you write. This will make the rest of the process faster and ensure you don’t break core functionality.</p>\n<p>Second, don’t worry about writing pretty code. If you find yourself debating what to name a variable, call it <code>thing1</code> and move on. Use formatting tools like <a href=\"https://prettier.io\">Prettier</a> to avoid thinking about white space and semicolons.</p>\n<p>Finally, try to go fast here. You only need working code. If you hit a roadblock, start over. <a href=\"https://medium.com/swlh/coding-faster-make-it-work-then-make-it-good-6aa988ebd8ab\">Writing sloppy code</a> at the beginning can help you arrive faster at a better solution.</p>\n<h2 id=\"make-it-always-work\" tabindex=\"-1\">Make it always work<a class=\"c-anchor-link\" href=\"#make-it-always-work\" aria-label=\"permalink\" aria-describedby=\"make-it-always-work\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Now we shift our attention to edge cases, cases involving less-common or unique data sets. These are the areas where bugs tend to show up. Here are some scenarios you might want to consider:</p>\n<ul>\n<li>No data</li>\n<li>A single piece of data</li>\n<li>The maximum amount of data</li>\n<li>One less than the maximum amount</li>\n<li>Bad (malformed) data</li>\n</ul>\n<p>If your code involves asynchronous calls:</p>\n<ul>\n<li>Rejected promises</li>\n<li>A promise that never resolves</li>\n<li>Slow responses</li>\n<li>Immediate responses</li>\n</ul>\n<p>Again, take the time to write tests. Whether you follow test-driven development or write tests after the fact, they will be invaluable as you move up the layers of concerns.</p>\n<h2 id=\"make-it-work-for-everyone\" tabindex=\"-1\">Make it work for everyone<a class=\"c-anchor-link\" href=\"#make-it-work-for-everyone\" aria-label=\"permalink\" aria-describedby=\"make-it-work-for-everyone\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>JavaScript is a funny language in that you can never be sure of the execution environment. Identify your feature’s core functionality and make sure it works in a wide variety of browsers. Having a list of your code’s official browser support helps in this step.</p>\n<p>There are two approaches to supporting multiple environments: <a href=\"https://www.smashingmagazine.com/2009/04/progressive-enhancement-what-it-is-and-how-to-use-it/\">progressive enhancement</a> and <a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Graceful_degradation\">graceful degradation</a>. Both involve detecting feature support, but progressive enhancement adds functionality while graceful degradation removes functionality.</p>\n<p>Both approaches are viable in different scenarios, and which you use depends on the context of the functionality.</p>\n<h2 id=\"make-it-right\" tabindex=\"-1\">Make it right<a class=\"c-anchor-link\" href=\"#make-it-right\" aria-label=\"permalink\" aria-describedby=\"make-it-right\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The next layer of focus is making the code right. <em>Right</em> means making the code readable and maintainable. All of the tests written up to this point pay off by giving you confidence that functionality remains.</p>\n<p>Developers read code much more than write it, so taking the time to make your code readable will help your colleagues and your future self. Readable code is more maintainable and extendable. The small cost of refactoring now can have an exponential impact on future project development.</p>\n<p>Focus on small changes that make a noticeable impact. Use domain-specific variable names, ensure your functions are in the correct scope, use comments as indicators for creating functions. I recommend reading Martin Fowler’s excellent book <a href=\"https://www.amazon.com/Refactoring-Improving-Existing-Addison-Wesley-Signature/dp/0134757599/ref=pd_lpo_14_t_0/135-0301302-4311004?_encoding=UTF8&amp;pd_rd_i=0134757599&amp;pd_rd_r=b0b344db-197c-486e-844c-ca016c5ce3de&amp;pd_rd_w=3V0TA&amp;pd_rd_wg=3BK50&amp;pf_rd_p=16b28406-aa34-451d-8a2e-b3930ada000c&amp;pf_rd_r=S5WMMCDX49SEKYDQBFEN&amp;psc=1&amp;refRID=S5WMMCDX49SEKYDQBFEN\">Refactoring</a> for more specific guidance and practical advice.</p>\n<h2 id=\"make-it-fast-(if-needed)\" tabindex=\"-1\">Make it fast (if needed)<a class=\"c-anchor-link\" href=\"#make-it-fast-(if-needed)\" aria-label=\"permalink\" aria-describedby=\"make-it-fast-(if-needed)\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>After we’ve made the code work, considered edge cases, added fallback support, and made the code readable, we finally optimize performance. Maybe.</p>\n<p>The first rule from the <a href=\"https://wiki.c2.com/?RulesOfOptimization\">Rules of Optimization</a> is don’t optimize. If you must optimize, however, there are a few things to keep in mind.</p>\n<p>First, make sure you are testing production code. Many frameworks bolt-on functionality and tools that help the development process but hinder performance. Production builds exclude this extra functionality, so ensuring you are testing in the right environment keeps you from optimizing performance unnecessarily.</p>\n<p>Next, you need to get baseline measurements. These will ensure that your optimizations worked. If possible, emulate slow internet connections and throttle CPU speed, two features <a href=\"https://developers.google.com/web/tools/chrome-devtools/evaluate-performance\">Chrome’s devtools</a> offers.</p>\n<p>One thing to keep in mind as you optimize is how your optimizations may affect the readability and maintainability of code. Usually, the most optimized solution is nowhere near the most readable. Always favor readable code.</p>\n<h2 id=\"summary\" tabindex=\"-1\">Summary<a class=\"c-anchor-link\" href=\"#summary\" aria-label=\"permalink\" aria-describedby=\"summary\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Performance optimization makes sense to developers because it’s something that’s easily measured. Optimizing code may be a more attractive goal than finding edge cases or making code more readable but should be avoided until the end of the process. Optimizing at the very end forces developers to focus on writing working, maintainable code.</p>\n<p>So, thanks for making it to the end! If you found this helpful, please let me know by liking this article on DEV Community and following me to know when I post a new article. And ask me all the questions you’d like (preferably about this article, but no judgment) on <a href=\"https://twitter.com/therealboone\">Twitter</a>.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-03-10T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/what-i-learned-blogging-daily-for-a-month/",
      "url": "https://www.falldowngoboone.com/blog/what-i-learned-blogging-daily-for-a-month/",
      "title": "What I learned blogging daily for a month",
      "content_html": "<p>I recently challenged myself to <a href=\"https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/\">write a blog post every day for a month</a>. Up to that point, I had only written eight blog posts for two years. A month later, not only do I have 28 new blog posts, I’ve learned some valuable lessons about my blogging process and my website. I wanted to share things about the experience that worked for me and issues I discovered that need attention.</p>\n<h2 id=\"worked%3A-setting-deadlines\" tabindex=\"-1\">Worked: Setting deadlines<a class=\"c-anchor-link\" href=\"#worked%3A-setting-deadlines\" aria-label=\"permalink\" aria-describedby=\"worked%3A-setting-deadlines\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>It’s surprising how an unmoving date can motivate you to complete a post. One of my recurring issues with blogging has been the tendency to overwork a piece until I completely lose interest. Experience has taught me that time is the biggest enemy of posting, and firm deadlines force you to throw away what’s not working and focus on what is.</p>\n<p>Being accountable to others dramatically increases the power of deadlines. One of my blogging rules involved announcing in my Twitter feed that I was posting daily. In my mind, I felt like I was accountable to a large audience. Social pressure works, even if it’s imaginary<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup>.</p>\n<h2 id=\"worked%3A-having-a-healthy-backlog\" tabindex=\"-1\">Worked: Having a healthy backlog<a class=\"c-anchor-link\" href=\"#worked%3A-having-a-healthy-backlog\" aria-label=\"permalink\" aria-describedby=\"worked%3A-having-a-healthy-backlog\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In the middle of February, we experienced the second coldest temperatures ever recorded in North Texas (-2℉, -17℃). That may not be cold for some of you reading this, but our state’s infrastructure is poorly prepared for temperatures that cold. Power generation froze up, and several utility buildings lost power, including our water station. Some were without power and water for a week.</p>\n<p>I barely wrote during that week, yet I stayed on schedule thanks to my backlog, a running list of ideas in Notion that I use to build out full posts. Sometimes an article I’ve been working on just isn’t working, so it’s nice to have a safety net.</p>\n<h2 id=\"worked%3A-cross-publishing-on-dev\" tabindex=\"-1\">Worked: Cross-publishing on DEV<a class=\"c-anchor-link\" href=\"#worked%3A-cross-publishing-on-dev\" aria-label=\"permalink\" aria-describedby=\"worked%3A-cross-publishing-on-dev\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I decided at the suggestion of <a href=\"https://twitter.com/5t3ph\">Stephanie Eckles</a> to cross-publish to DEV Community. Cross-publishing ended up being a great decision because DEV’s platform exposed me to a bigger audience than I ever would’ve received on my blog. Coupled with the motivation and encouragement I received from comments and reader interaction, I’ve decided to continue doing this for all posts.</p>\n<p>There are, however, some challenges I’ve found cross-publishing, mainly due to differences in platforms. My site is built in Eleventy, and my front matter formatting doesn’t completely align with DEV’s. There are also differences in how I mark up embedded content. If you notice, hardly any of my posts have CodePens embedded, and I didn’t use any images.</p>\n<p>Now that I have some time, I’m going to start ironing out these issues, starting with images. That’s a topic I need to address on my site first, which brings me to my first thing that didn’t work.</p>\n<h2 id=\"did-not-work%3A-my-website-styling-is-lacking\" tabindex=\"-1\">Did not work: My website styling is lacking<a class=\"c-anchor-link\" href=\"#did-not-work%3A-my-website-styling-is-lacking\" aria-label=\"permalink\" aria-describedby=\"did-not-work%3A-my-website-styling-is-lacking\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In terms of my blog, <a href=\"https://www.falldowngoboone.com\">falldowngoboone</a>, I discovered many rough edges throughout the month. One such issue that comes to mind is an excerpt filter I created<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">[2]</a></sup>, which unfortunately doesn’t process Markdown properly. If anything in the first 20 words of a post contains Markdown, it’s not processed, and if there are any special characters, they are escaped.</p>\n<p>It also appears some of the code blocks that Notion produces use a syntax I don’t support. I know that may not seem like a big deal, but it’s broken syntax highlighting on my site. This should be an easy fix.</p>\n<p>Finally, my home page needs an overhaul. When I had only eight posts, it was easy to find them. Now, it’s getting a bit ridiculous. I plan to completely change the homepage design, featuring the most popular articles, my most recent posts, and a link to post archives. I may even add a search (gasp!) at some point.</p>\n<h2 id=\"did-not-work%3A-my-publishing-process-sucks\" tabindex=\"-1\">Did not work: My publishing process sucks<a class=\"c-anchor-link\" href=\"#did-not-work%3A-my-publishing-process-sucks\" aria-label=\"permalink\" aria-describedby=\"did-not-work%3A-my-publishing-process-sucks\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Near the end of the month, I wrote about <a href=\"https://www.falldowngoboone.com/blog/how-i-write-my-posts/\">how I write my posts</a>, and I briefly mentioned some ideas I had for optimizing my publishing flow. Currently, I walk through at least 18 different steps to publish a single blog piece. I think better tools and well-planned automation can reduce those steps.</p>\n<p>Notion, as I’m currently using it, doesn’t fit with my publishing process. Unfortunately, its exported Markdown output doesn’t align with the format I use in Eleventy. It would be nice if Notion offered a way to tweak the export formats, but I understand that constraints like this are necessary to allow flexibility in other areas.</p>\n<p>One idea I have is to write a script that could convert the exported metadata into front matter. Another idea is to change to a full content management solution, like Sanity. Scripting a solution would mean I could keep using Notion, with the downside of maintenance. Using Sanity would give me a streamlined publishing solution with little toil. I’m still weighing my options here (and I’ll make sure to write about whatever choice I make).</p>\n<p>Finally, there are areas of my process best suited for automation. My article backlog includes a status flag (Planned, In Progress, and Published<sup class=\"footnote-ref\"><a href=\"#fn3\" id=\"fnref3\">[3]</a></sup>). I’d love to figure out a way to automate In Progress when I schedule the piece and Published once the post has merged.</p>\n<h2 id=\"what-next%3F\" tabindex=\"-1\">What next?<a class=\"c-anchor-link\" href=\"#what-next%3F\" aria-label=\"permalink\" aria-describedby=\"what-next%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I will not continue to blog daily, as insightful as it’s been. But I will focus on creating blog posts at a regular frequency, at least once a week. I hope to improve my communication skills and connect with more amazing people through DEV Community.</p>\n<p>Finally, if you’re thinking about blogging, do it. Don’t worry about whether or not you have something to say. When I began blogging, I was afraid I wouldn’t have anything to say. Now I can’t stop writing.</p>\n<p>That’s it for now. If you found this helpful, please let me know by liking this post on DEV Community and following me so you know when I publish. And if you have any questions, don’t hesitate to reach out to me on Twitter.</p>\n<p>Until next time!</p>\n<h2 id=\"most-popular-posts\" tabindex=\"-1\">Most popular posts<a class=\"c-anchor-link\" href=\"#most-popular-posts\" aria-label=\"permalink\" aria-describedby=\"most-popular-posts\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In case you’re interested, here are my most popular articles from February:</p>\n<ol>\n<li><a href=\"https://dev.to/falldowngoboone/how-to-avoid-premature-abstraction-in-react-5672\">How to avoid premature abstraction in React</a></li>\n<li><a href=\"https://dev.to/falldowngoboone/share-variables-between-javascript-and-css-5ad0\">Share variables between JavaScript and CSS</a></li>\n<li><a href=\"https://dev.to/falldowngoboone/how-i-write-my-posts-4538\">How I write my posts</a></li>\n</ol>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>If you’d like to learn more about different techniques to help you become consistent at blogging or any other habit, check out <em>Atomic Habits</em> by James Clear. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>In case you didn’t know, fdgb runs on <a href=\"https://www.11ty.dev\">Eleventy</a>, a JavaScript-based static site generator that’s a joy to use. Filters in Eleventy act like functions that can transform your blog’s content. They are simple yet powerful. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn3\" class=\"footnote-item\"><p>I’m not completely happy with these names, but they work for now. <a href=\"#fnref3\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-03-04T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/share-variables-between-javascript-and-css/",
      "url": "https://www.falldowngoboone.com/blog/share-variables-between-javascript-and-css/",
      "title": "Share variables between JavaScript and CSS",
      "content_html": "<p>Whether you need site breakpoints for <code>matchMedia</code> or access to theme colors, sharing values between your JavaScript and CSS is sometimes unavoidable. The easiest solution is to <a href=\"https://www.falldowngoboone.com/blog/understand-the-context-of-code-you-copy/\">copy and paste</a> values, but how can you ensure values stay synchronized when that brand blue color changes to indigo?</p>\n<p>The answer is to create a single source of truth by sharing values between the JavaScript and style layers. There are several ways to accomplish this, and the best approach for a project depends on its frontend stack. Here are all of the ways I know how to pass data back and forth between all the layers.</p>\n<h2 id=\"icss\" tabindex=\"-1\">ICSS<a class=\"c-anchor-link\" href=\"#icss\" aria-label=\"permalink\" aria-describedby=\"icss\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p><a href=\"https://css-tricks.com/css-modules-part-1-need/\">CSS Modules</a>, gives us two ways of sharing variables, the <a href=\"https://github.com/css-modules/icss\">Interoperable CSS</a> (ICSS) spec and the PostCSS Modules Values spec. ICSS appears to be the older of the two specifications, so I’ll start there.</p>\n<p>ICSS is a low-level specification that’s mainly for loader authors. It describes how to treat CSS modules as JavaScript dependencies and introduces the <code>:export</code> directive to act as a way to export defined values. Coupled with Sass variables, it allows you to export theme values:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token comment\">// colors.module.scss</span><br><span class=\"token comment\">// assuming this is within Create React App; the `.module` lets CRA know</span><br><span class=\"token comment\">// this is a CSS Module</span><br><br><span class=\"token property\"><span class=\"token variable\">$my-red</span></span><span class=\"token punctuation\">:</span> #ff0000<span class=\"token punctuation\">;</span><br><br><span class=\"token selector\">:export </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">myRed</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">$my-red</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The exported values are imported like much like any other JavaScript module:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// MyComponent.js</span><br><span class=\"token comment\">// assuming this is within Create React App</span><br><br><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> colors <span class=\"token keyword\">from</span> <span class=\"token string\">'theme/colors.module.scss'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">MyComponent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">myRed's value: </span><span class=\"token punctuation\">{</span>colors<span class=\"token punctuation\">.</span>myRed<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The above should work in Create React App out of the box. If you are rolling your own Webpack configuration (may God have mercy on your soul), you’ll need to <a href=\"https://github.com/webpack-contrib/css-loader#compiletype\">configure <code>modules</code> with a <code>compileType</code> of <code>icss</code></a>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">module</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token literal-property property\">rules</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br>      <span class=\"token punctuation\">{</span><br>        <span class=\"token literal-property property\">test</span><span class=\"token operator\">:</span> <span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">\\.css$</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">i</span></span><span class=\"token punctuation\">,</span><br>        <span class=\"token literal-property property\">loader</span><span class=\"token operator\">:</span> <span class=\"token string\">\"css-loader\"</span><span class=\"token punctuation\">,</span><br>        <span class=\"token literal-property property\">options</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>          <span class=\"token literal-property property\">modules</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br>            <span class=\"token literal-property property\">compileType</span><span class=\"token operator\">:</span> <span class=\"token string\">\"icss\"</span><span class=\"token punctuation\">,</span><br>          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<ul>\n<li>CSS is the source of truth</li>\n<li>Great solution if you’re using Create React App</li>\n<li>Webpack configuration could be a challenge</li>\n<li>Aimed more at library authors than app developers</li>\n<li>Non-standard CSS</li>\n</ul>\n<h2 id=\"setting-%40value\" tabindex=\"-1\">Setting <code>@value</code><a class=\"c-anchor-link\" href=\"#setting-%40value\" aria-label=\"permalink\" aria-describedby=\"setting-%40value\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>CSS Modules also offers <a href=\"https://github.com/css-modules/postcss-modules-values\">the <code>@value</code> directive</a>, which explicitly defines module values. <code>@value</code> can also be used to import values from other CSS modules. It’s a catchall solution for passing values to and from CSS modules to anywhere.</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token comment\">// breakpoints.module.css</span><br><br>@value <span class=\"token property\">larry</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">(</span><span class=\"token property\">max-width</span><span class=\"token punctuation\">:</span> 599px<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>@value <span class=\"token property\">moe</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">(</span><span class=\"token property\">min-width</span><span class=\"token punctuation\">:</span> 600px<span class=\"token punctuation\">)</span> <span class=\"token operator\">and</span> <span class=\"token punctuation\">(</span><span class=\"token property\">max-width</span><span class=\"token punctuation\">:</span> 959px<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>@value <span class=\"token property\">curly</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">(</span><span class=\"token property\">min-width</span><span class=\"token punctuation\">:</span> 960px<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token comment\">// MyComponent.module.css</span><br><span class=\"token comment\">// this is one of the multiple ways you can import @value definitions</span><br><span class=\"token comment\">// see https://github.com/css-modules/postcss-modules-values</span><br><br>@value larry<span class=\"token punctuation\">,</span> moe<span class=\"token punctuation\">,</span> curly <span class=\"token keyword\">from</span> <span class=\"token string\">\"theme/breakpoints.module.css\"</span><span class=\"token punctuation\">;</span><br><br><span class=\"token atrule\"><span class=\"token rule\">@media</span> larry</span> <span class=\"token punctuation\">{</span><br>  ...<br><span class=\"token punctuation\">}</span><br><br><span class=\"token atrule\"><span class=\"token rule\">@media</span> moe</span> <span class=\"token punctuation\">{</span><br>  ...<br><span class=\"token punctuation\">}</span><br><br><span class=\"token atrule\"><span class=\"token rule\">@media</span> curly</span> <span class=\"token punctuation\">{</span><br>  ...<br><span class=\"token punctuation\">}</span></code></pre>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// MyComponent.module.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> Media <span class=\"token keyword\">from</span> <span class=\"token string\">'react-media'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> larry<span class=\"token punctuation\">,</span> moe<span class=\"token punctuation\">,</span> curly <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'theme/breakpoints.module.css'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">MyComponent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Media</span></span> <span class=\"token attr-name\">queries</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> larry<span class=\"token punctuation\">,</span> moe<span class=\"token punctuation\">,</span> curly <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token punctuation\">{</span><span class=\"token parameter\">matches</span> <span class=\"token operator\">=></span><br>        matches<span class=\"token punctuation\">.</span>larry <br>          <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span><br>            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Oh, a wise guy, eh?</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>          <span class=\"token punctuation\">)</span> <br>          <span class=\"token operator\">:</span> matches<span class=\"token punctuation\">.</span>moe <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span><br>            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Why I outta...</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>          <span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><br>            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Nyuk nyuk</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>        <span class=\"token punctuation\">)</span><br>      <span class=\"token punctuation\">}</span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Media</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<ul>\n<li>CSS is the source of truth</li>\n<li>Easy to implement in Create React App</li>\n<li>Again, Webpack (meh)</li>\n<li>Appears to be more of a dev-friendly solution</li>\n<li>Allows you to share values between CSS modules</li>\n<li>Non-standard CSS</li>\n</ul>\n<h2 id=\"sass-compiler\" tabindex=\"-1\">Sass compiler<a class=\"c-anchor-link\" href=\"#sass-compiler\" aria-label=\"permalink\" aria-describedby=\"sass-compiler\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Sass’s JavaScript API can add custom functions by defining the <a href=\"https://sass-lang.com/documentation/js-api#functions\"><code>functions</code> option of <code>render</code></a>. You can use this to define getter functions that return your theme’s values directly in Sass. I implemented this on our website using <code>node-sass</code>, which exposes the <code>functions</code> option in its CLI:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\">node-sass src/styles/ -o build/styles --functions path/to/sass-functions.js</code></pre>\n<p>And the <code>sass-functions.js</code> file looks like this:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// sass-functions.js</span><br><br><span class=\"token keyword\">const</span> sass <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'node-sass'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> theme <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../theme/index.js'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token string-property property\">'getColorMap()'</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">entries</span><span class=\"token punctuation\">(</span>theme<span class=\"token punctuation\">.</span>colors<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">reduce</span><span class=\"token punctuation\">(</span><br>      toSassMap<span class=\"token punctuation\">,</span><br>      <span class=\"token keyword\">new</span> <span class=\"token class-name\">sass<span class=\"token punctuation\">.</span>types<span class=\"token punctuation\">.</span>Map</span><span class=\"token punctuation\">(</span>Object<span class=\"token punctuation\">.</span><span class=\"token function\">keys</span><span class=\"token punctuation\">(</span>theme<span class=\"token punctuation\">.</span>colors<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br>  <span class=\"token string-property property\">'getMqMap()'</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">entries</span><span class=\"token punctuation\">(</span>theme<span class=\"token punctuation\">.</span>mqs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">reduce</span><span class=\"token punctuation\">(</span><br>      toSassMap<span class=\"token punctuation\">,</span><br>      <span class=\"token keyword\">new</span> <span class=\"token class-name\">sass<span class=\"token punctuation\">.</span>types<span class=\"token punctuation\">.</span>Map</span><span class=\"token punctuation\">(</span>Object<span class=\"token punctuation\">.</span><span class=\"token function\">keys</span><span class=\"token punctuation\">(</span>theme<span class=\"token punctuation\">.</span>mqs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">toSassMap</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">list<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">,</span> value<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> idx</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  list<span class=\"token punctuation\">.</span><span class=\"token function\">setKey</span><span class=\"token punctuation\">(</span>idx<span class=\"token punctuation\">,</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">sass<span class=\"token punctuation\">.</span>types<span class=\"token punctuation\">.</span>String</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  list<span class=\"token punctuation\">.</span><span class=\"token function\">setValue</span><span class=\"token punctuation\">(</span>idx<span class=\"token punctuation\">,</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">sass<span class=\"token punctuation\">.</span>types<span class=\"token punctuation\">.</span>String</span><span class=\"token punctuation\">(</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">return</span> list<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Note that I’m having to define Sass types. The <code>getColorMap()</code> and <code>getMqMap()</code> functions return Sass maps that include all of our theme variables. Very handy!</p>\n<p>Unfortunately, <a href=\"https://sass-lang.com/blog/libsass-is-deprecated\">LibSass, the core engine of <code>node-sass</code>, has been deprecated</a>, along with <code>node-sass</code>. The canonical Dart version of Sass lacks a nice CLI option for custom functions. If you want to recreate this functionality, you’re stuck building a compiler using Dart Sass’s JavaScript API.</p>\n<ul>\n<li>JavaScript (or JSON) is the source of truth</li>\n<li>Requires Sass</li>\n<li>Easy to implement with <code>node-sass</code>, but it’s deprecated<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup></li>\n<li>You have to role your own compilation if you want to define custom functions in Dart Sass</li>\n</ul>\n<h2 id=\"css-in-js\" tabindex=\"-1\">CSS-in-JS<a class=\"c-anchor-link\" href=\"#css-in-js\" aria-label=\"permalink\" aria-describedby=\"css-in-js\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>A common variable sharing solution in React is to simply let JavaScript do all the work. And as controversial as <a href=\"https://css-tricks.com/the-differing-perspectives-on-css-in-js/\">CSS-in-JS</a> seems to be, it presents an easy way to share variables simply because you are defining CSS in a JavaScript file.</p>\n<p>Here’s how you might share a variable in the library <a href=\"https://emotion.sh/docs/introduction\">Emotion</a>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> css<span class=\"token punctuation\">,</span> cx <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@emotion/css'</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> colors <span class=\"token keyword\">from</span> <span class=\"token string\">'./theme.colors.js'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><br>    <span class=\"token attr-name\">className</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>css<span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"><br>      color: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>colors<span class=\"token punctuation\">.</span>primary<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">;<br>      &amp;:hover {<br>        color: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>colors<span class=\"token punctuation\">.</span>secondary<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">;<br>      }<br>    </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span></span><br>  <span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    I get so emotional, baby.<br>  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token punctuation\">)</span></code></pre>\n<p>I mean, it’s easy. It’s so easy that I’d debate whether or not this is classified as sharing variables between JavaScript and CSS, but I’m throwing it in anyway.</p>\n<p>I’ve already mentioned Emotion, but other CSS-in-JS libraries to check out include <a href=\"https://styled-components.com\">Styled Components</a>, <a href=\"https://cssinjs.org/\">JSS</a>, <a href=\"https://theme-ui.com\">Theme-UI</a>, <a href=\"https://formidable.com/open-source/radium/\">Radium</a>, and <a href=\"https://github.com/Khan/aphrodite\">Aprhodite</a>.</p>\n<ul>\n<li>JavaScript (or JSON) is the source of truth</li>\n<li>Good option for shared React component libraries</li>\n<li>Requires JavaScript to apply styles (no JS, no styles)</li>\n<li>Non-standard CSS</li>\n</ul>\n<h2 id=\"custom-properties\" tabindex=\"-1\">Custom Properties<a class=\"c-anchor-link\" href=\"#custom-properties\" aria-label=\"permalink\" aria-describedby=\"custom-properties\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you need a lightweight, “proper” way to share variables between JavaScript and CSS, look no further than Custom Properties. Custom Properties allow you to create arbitrary CSS properties and set them to any value you want.</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token selector\">:root</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token property\">--color-brand</span><span class=\"token punctuation\">:</span> #BADA55<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--color-secondary</span><span class=\"token punctuation\">:</span> #005DAB<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">MyComponent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> brandColor <span class=\"token operator\">=</span> <span class=\"token function\">getComputedStyle</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">)</span><br>    <span class=\"token punctuation\">.</span><span class=\"token function\">getPropertyValue</span><span class=\"token punctuation\">(</span><span class=\"token string\">'--color-brand'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <br>  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span> <span class=\"token attr-name\">style</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">color</span><span class=\"token operator\">:</span> brandColor <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">I'm brand color!</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>If you access these properties a lot, you may want to create a utility function to save on typing:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token keyword\">function</span> cssValue<span class=\"token punctuation\">(</span>property<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token builtin class-name\">return</span> getComputedStyle<span class=\"token punctuation\">(</span>document.documentElement<span class=\"token punctuation\">)</span><br>    .getPropertyValue<span class=\"token punctuation\">(</span>property<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Custom Properties are completely standard CSS spec, and this is the only solution that is dynamic, meaning properties can change based on context:</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token selector\">:root</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token property\">--color-brand</span><span class=\"token punctuation\">:</span> #BADA55<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--color-secondary</span><span class=\"token punctuation\">:</span> #005DAB<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token atrule\"><span class=\"token rule\">@media</span> <span class=\"token punctuation\">(</span><span class=\"token property\">prefers-color-scheme</span><span class=\"token punctuation\">:</span> dark<span class=\"token punctuation\">)</span><br>  <span class=\"token punctuation\">:</span>root</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token property\">--color-brand</span><span class=\"token punctuation\">:</span> white<span class=\"token punctuation\">;</span><br>    <span class=\"token property\">--color-secondary</span><span class=\"token punctuation\">:</span> #ccc<span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>When you access those properties, they’ll be different depending on the user’s preferences. This is incredibly powerful.</p>\n<ul>\n<li>CSS is the source of truth</li>\n<li>Context-specific (CSS updates custom properties live based on the context)</li>\n<li>Easy to implement</li>\n<li>Not supported in Internet Explorer 11, but you can sort of <a href=\"https://www.npmjs.com/package/ie11-custom-properties\">polyfill</a> it</li>\n<li>Can’t use Custom Properties for breakpoints 😩</li>\n<li>Standard CSS</li>\n</ul>\n<h2 id=\"lots-of-options\" tabindex=\"-1\">Lots of options<a class=\"c-anchor-link\" href=\"#lots-of-options\" aria-label=\"permalink\" aria-describedby=\"lots-of-options\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Sharing variables between CSS and JavaScript can help reduce toil and cut down on unintentional tech debt. And if you need to, you have no shortage of options. Just make sure you understand what you want to act as the source of truth and know your technical requirements.</p>\n<p>If you found that helpful, please let me know by liking this post on DEV Community and sharing it. And if you want more articles like this, make sure you <a href=\"https://twitter.com/therealboone\">follow me on Twitter</a> so you’ll know when I post new ones.</p>\n<p>Until next time!</p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Trust me when I say you should not use <code>node-sass</code>. It’s so buggy that it can’t process newer CSS. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-02-28T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/how-i-write-my-posts/",
      "url": "https://www.falldowngoboone.com/blog/how-i-write-my-posts/",
      "title": "How I write my posts",
      "content_html": "<p>I’ve been posting a <a href=\"https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/\">new article every day this month</a>, and it’s been interesting. I’ll write about that soon, but today I want to share how I put these posts together. Hopefully, you’ll learn something new from my process, or see how terrible my process is and give me some advice.</p>\n<h2 id=\"idea-backlog\" tabindex=\"-1\">Idea backlog<a class=\"c-anchor-link\" href=\"#idea-backlog\" aria-label=\"permalink\" aria-describedby=\"idea-backlog\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you’re going to create content, you need a steady stream of ideas. I keep a backlog so I can store notes, write drafts, and constantly reassess what to post next. This post you’re reading? It started out in my backlog.</p>\n<p>You can keep an idea backlog in whatever tool you use. I use <a href=\"https://www.notion.so/\">Notion</a> for a few reasons. First, I can access Notion on anything that’s connected to the internet, so I can capture an idea before I forget it. Second, Notion gives me the flexibility to organize my content however I want.</p>\n<p>For Blogruary, I created a special post in Notion with a list view of all posts tagged “blograry” (each view can have its own special filtering and sorting). This allows me to get a quick look at all the ideas available to me.</p>\n<p>For more information on using Notion as a project manager, check out this <a href=\"https://youtu.be/32dLXdB4ozs\">Notion masterclass video from Thomas Frank</a>.</p>\n<h2 id=\"writing-the-post\" tabindex=\"-1\">Writing the post<a class=\"c-anchor-link\" href=\"#writing-the-post\" aria-label=\"permalink\" aria-describedby=\"writing-the-post\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>After adding an idea to the backlog, I paste links to relevant material as well as notes into the created entry. This eventually becomes the blog post itself. Depending on how far along the information is, I’ll go ahead and schedule the publish date.</p>\n<p>If I’m being honest, this process has been all over the place. Sometimes I’ll start the post without any notes, or the post is a long list of notes until the day I have to post. Many times I’m stuck writing and editing the entire post the day I’m supposed to publish (like today).</p>\n<p>I’ve also noticed some issues with writing blog posts in Notion, mainly because of all the manual changes I have to make to the exported Markdown. I’m still trying to figure this part of the process out.</p>\n<h2 id=\"publishing\" tabindex=\"-1\">Publishing<a class=\"c-anchor-link\" href=\"#publishing\" aria-label=\"permalink\" aria-describedby=\"publishing\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>After I’ve written a post, I’ll export it from Notion as Markdown, drop it into my blog’s source code, and manually format the <a href=\"https://www.11ty.dev/docs/data-frontmatter/\">front matter for Eleventy</a>. Unfortunately, Notion doesn’t output front matter, nor does it allow me to customize how associated data is displayed. This would be a welcome feature.</p>\n<p>I’ve started to run the post content through <a href=\"https://app.grammarly.com\">Grammarly</a> to correct any grammar mistakes. Grammarly has extensions for all the major browsers, as well as a desktop app that allows you to create a new document for analysis (big thanks to <a href=\"https://twitter.com/5t3ph\">Stephanie Eckles</a> for that tip). It’s free to use the basic features, but I’m considering upgrading.</p>\n<p>After making corrections in Grammarly, I’ll paste the corrections back into the Markdown file in VS Code, commit the changes, and push them up to GitHub.</p>\n<p>After creating a pull request, <a href=\"https://www.netlify.com\">Netlify</a> runs a series of checks. While that happens, I create a duplicate of the post on DEV Community. I have to add a <a href=\"https://dev.to/michaelburrows/comment/125j0\">canonical URL</a> back to my website so I don’t get penalized for duplicate content, but in order to do that, I need to publish on <a href=\"https://www.falldowngoboone.com\">my personal blog</a> first.</p>\n<p>By the time I’ve set up a draft in DEV, my pull request has been verified and is ready to merge. The merge kicks off a deployment to Netlify (yay Netlify!). After merging, I grab the post’s URL, add it to the DEV post, then I hit publish.</p>\n<h2 id=\"thoughts-on-the-process\" tabindex=\"-1\">Thoughts on the process<a class=\"c-anchor-link\" href=\"#thoughts-on-the-process\" aria-label=\"permalink\" aria-describedby=\"thoughts-on-the-process\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So that’s what I’ve been doing this entire month. I learned that Notion is a great tool for organizing and writing, but I need a tool that’s closer to the end product. I’m starting to look at <a href=\"https://www.sanity.io\">Sanity</a> as a viable option.</p>\n<p>I’ve also been thinking about streamlining the publishing process by automating the duplicate post to DEV. Challenges include differences in front matter and markup. If I can limit myself to only shared markup, that would make the automation much easier.</p>\n<p>Finally, if you’re thinking about starting a blog, a good place to start is signing up for the <a href=\"https://bloggingfordevs.com\">Blogging for Devs</a> newsletter from Monica Lent. New subscriptions start with a 7-day blogging course sent directly to your inbox, followed by regular emails filled with tips for content makers.</p>\n<p>I will be expanding on the rest of what I’ve learned in a future post, so if you want to know when that comes out, follow <a href=\"https://twitter.com/therealboone\">me on Twitter</a>. And if you found this post helpful, please let me know by liking it on DEV Community.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-02-27T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/understand-the-context-of-code-you-copy/",
      "url": "https://www.falldowngoboone.com/blog/understand-the-context-of-code-you-copy/",
      "title": "Understand the context of code you copy",
      "content_html": "<p>If a problem is too difficult to solve on our own, sometimes the only course of action is to search, copy, and paste. It’s something all developers have done regardless of their experience level.</p>\n<p>While there is no shame in copying and pasting code, it can lead to a mess. That’s why I have one copy-paste rule that I follow: <strong>understand the context.</strong></p>\n<h2 id=\"a-reason-for-everything\" tabindex=\"-1\">A reason for everything<a class=\"c-anchor-link\" href=\"#a-reason-for-everything\" aria-label=\"permalink\" aria-describedby=\"a-reason-for-everything\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Requirements, constraints, and assumptions all play a role in how we write code. Unless you’ve found a generic solution, the code you copy comes with a context that may not apply to your situation.</p>\n<p>The wrong context could cause you to miss story requirements or cause other code to break (e.g. variable name collisions). Taking time to understand the context can help save you and your teammates a headache down the road.</p>\n<h2 id=\"learning-the-context\" tabindex=\"-1\">Learning the context<a class=\"c-anchor-link\" href=\"#learning-the-context\" aria-label=\"permalink\" aria-describedby=\"learning-the-context\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Throughout my experience of dealing with copied and pasted code, I’ve seen a few common problems. These can be avoided by asking yourself some questions as you <em>carefully read the code.</em></p>\n<ul>\n<li><strong>Does this code rely on global state?</strong> This is a common issue with legacy JavaScript codebases that rely on the global Window object to pass data and functions around. If you can, move this code out of global scope. It will help you answer the remaining questions.</li>\n<li><strong>Is there anything that looks unfamiliar?</strong> Are there APIs used that don’t look familiar to you? Look them up and make sure you understand what they are used for and why. Identifying unfamiliar APIs and methods informs the code’s context, but it’s also an opportunity for you to learn something new.</li>\n<li><strong>Is there anything unnecessary?</strong> Dead code in a large codebase is scary. No one will touch it, either out of fear or because of the amount of work involved in tracking down usage. Hastily copying and pasting dead code multiplies this tech debt immeasurably. Trim unused code.</li>\n<li><strong>Do variable names match the domain?</strong> If you’re copying from an online source, variables will tend to have generic names. Taking the time to find better names <a href=\"https://www.falldowngoboone.com/blog/what-is-your-code-communicating/\">helps the code communicate better</a>, and captures the context.</li>\n<li><strong>Does this code have any dependencies?</strong> There are swaths of our codebase that use Require.js and therefore…require…it to be present. Sometimes it’s better to remove the need for that dependency by copying and pasting even more code, and sometimes it’s better to add the dependency. It all <em>depends</em> on the <em>context</em> (ah, see what I did there?).</li>\n<li><strong>Are there any new errors logged after pasting?</strong> The moment you paste code into your codebase, you should check your logging. This reduces the <a href=\"https://www.falldowngoboone.com/blog/the-feedback-loop/\">dev feedback loop</a> and informs you of any incompatibilities immediately.</li>\n</ul>\n<h2 id=\"this-looks-like-a-lot-of-work\" tabindex=\"-1\">This looks like a lot of work<a class=\"c-anchor-link\" href=\"#this-looks-like-a-lot-of-work\" aria-label=\"permalink\" aria-describedby=\"this-looks-like-a-lot-of-work\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>You may be thinking, <em>Geez, Ryan, this sounds like it’s going to take forever, and the reason I’m copying and pasting code is to save time.</em> And you’re right, this will add time to your solution. But that extra time will ensure that you solve the right problem, meet requirements, and reduce tech debt.</p>\n<p>Copying existing code can supercharge your team’s velocity, but remember this comes with a cost. If you don’t slow down and ask questions, chances are you’ll pay the price further down the road, and you’ll lose any short-term gains over the long term.</p>\n<h2 id=\"take-the-time-to-save-time\" tabindex=\"-1\">Take the time to save time<a class=\"c-anchor-link\" href=\"#take-the-time-to-save-time\" aria-label=\"permalink\" aria-describedby=\"take-the-time-to-save-time\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Sometimes copying and pasting existing code is the best course of action. But before do, take the time to understand and adapt the context. The time you spend will save you in the long run.</p>\n<p>If you’re still reading this, thanks for sticking around to the end! Unless you just skipped to the end. In which case, thanks for at least reading this? If you found this post helpful, please consider liking over on DEV Community, and make sure you <a href=\"https://twitter.com/therealboone\">follow me</a> so you know when I release a new post.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-02-26T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/13-fantastic-web-development-blogs/",
      "url": "https://www.falldowngoboone.com/blog/13-fantastic-web-development-blogs/",
      "title": "13 fantastic web development blogs",
      "content_html": "<p>There are some amazing web development blogs out there (<a href=\"https://www.smashingmagazine.com\">Smashing Magazine</a>, <a href=\"https://css-tricks.com\">CSS-Tricks</a> and <a href=\"http://tympanus.net/codrops/\">Codrops</a> come to mind), but today I want to pay homage to the humble personal blog. Here are some of my favorite web developer blogs in no particular order:</p>\n<ul>\n<li><a href=\"https://moderncss.dev\">Modern CSS</a> - Do you still struggle with vertical centering in CSS? This series from Stephanie Eckles is for you.</li>\n<li><a href=\"http://danmall.me\">Dan Mall</a> - Dan, the founder of the design collaborative <a href=\"https://superfriendlydesign.systems\">SuperFriendly</a>, is a generous source for all things design systems and client relations.</li>\n<li><a href=\"https://stuffandnonsense.co.uk/blog\">Stuff &amp; Nonsense</a> - Andy Clark has been building websites for a while, and he has a thing or two to teach about writing bulletproof CSS. His <em>Inspired Design Decisions</em> series is a must-read.</li>\n<li><a href=\"https://www.sarasoueidan.com/blog/\">Sara Soueidan</a> - I started following Sara a while back thanks to her amazing contributions to the Codrops blog. She is currently focusing on accessibility, but her SVG filter articles will blow your mind.</li>\n<li><a href=\"https://sarahmhigley.com\">Sarah Higley</a> - Sarah is a developer at Microsoft with a passion for accessibility. I learned about her through the fantastic A11y Slack group.</li>\n<li><a href=\"https://adrianroselli.com\">Adrian Roselli</a> - I read Adrian’s blog to learn how bad I am at accessibility.</li>\n<li><a href=\"https://benmyers.dev\">Ben Meyers</a> - I am lucky to know Ben personally through a local Meetup. His blog is filled with tons of great accessibility information. Oh, and make sure you check out his Twitch channel <a href=\"https://www.twitch.tv/someanticsdev\">Some Antics</a>!</li>\n<li><a href=\"https://www.joshwcomeau.com\">Josh Comeau</a> - In addition to posting some great frontend content, Josh has created a truly fun website. I want my blog to be like Josh’s when it grows up.</li>\n<li><a href=\"https://frankchimero.com\">Frank Chimero</a> - Frank is an accomplished web designer and writer. This site features dense engaging writing that will make you think. My favorite is <em><a href=\"https://frankchimero.com/blog/2015/the-webs-grain/\">The Web’s Grain</a></em>.</li>\n<li><a href=\"https://bradfrost.com\">Brad Frost</a> - He created Atomic Design. He plays bass. If you want to dive more into design systems, you need to follow Brad.</li>\n<li><a href=\"https://markboulton.co.uk\">Mark Boulton</a> - Mark’s writing has helped me bridge the gap between print and screen design. I highly recommend for developers <em>and</em> designers.</li>\n<li><a href=\"https://2ality.com\">2ality</a> - Dr. Axel Rauschmayer’s blog is a JavaScript developer’s dream. He features deep dives into the ES spec and explorations into brand-new JavaScript features.</li>\n<li><a href=\"https://rachelandrew.co.uk\">Rachel Andrew</a> - Rachel is an accomplished speaker, writer, and web developer. If you are passionate about CSS, this blog’s for you.</li>\n</ul>\n<p>Didn’t see your favorite? Please <a href=\"https://twitter.com/therealboone\">let me know on Twitter</a> who I need to add. And if you just discovered a new blog to follow from this post, please let me know by liking this on DEV Community. Likes, much like food, sustain me and give me the strength I need to face the day.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-02-25T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/how-to-get-your-pull-request-merged/",
      "url": "https://www.falldowngoboone.com/blog/how-to-get-your-pull-request-merged/",
      "title": "How to get your pull request merged",
      "content_html": "<p>When I started my first job as a professional developer, one of my biggest challenges was learning how to create helpful pull requests. I had been using git for a few years at that point, but my experience was limited to merging and pushing directly to the default remote branch. As a result, my first code reviews were fraught with answering questions, rewriting code, and (gulp) interactive rebasing.</p>\n<p>What follows is what I’ve learned from the past few years of crafting pull requests. My hope is they’ll help you whether you’re starting your first job in development or trying to contribute to your favorite open source project.</p>\n<h2 id=\"use-atomic-commits\" tabindex=\"-1\">Use atomic commits<a class=\"c-anchor-link\" href=\"#use-atomic-commits\" aria-label=\"permalink\" aria-describedby=\"use-atomic-commits\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Effective pull requests start with <a href=\"https://sparkbox.com/foundry/atomic_commits_with_git\">atomic commits</a>. Atomic commits add value, don’t break tests, and are the smallest unit of work possible. A list of such commits may look something like this:</p>\n<ul>\n<li>Add product metadata HTML</li>\n<li>Style product metadata</li>\n<li>Add product metadata JavaScript</li>\n</ul>\n<p>Each step in that list focuses on a particular domain of the overall task of adding product metadata, first the markup, then the CSS, and finally the behavior.</p>\n<p>Why use atomic commits? First of all, they’re easier to read in a code review (more on that in a minute). Second, since they’re self-contained, they’re easy to revert without breaking anything.</p>\n<p>Now that we have well-structured commits, we need to think about the commit message.</p>\n<h2 id=\"follow-commit-message-standards\" tabindex=\"-1\">Follow commit message standards<a class=\"c-anchor-link\" href=\"#follow-commit-message-standards\" aria-label=\"permalink\" aria-describedby=\"follow-commit-message-standards\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>As anyone who has ever plugged a lamp in a wall can tell you, standards are important<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup>. Different projects may have different commit message standards. Make sure you read and understand them before you contribute.</p>\n<p>If you can’t find any standards, here’s a great article on <a href=\"https://chris.beams.io/posts/git-commit/\">how to write commit messages</a>. My work more or less follows these standards. Here’s a high-level summary:</p>\n<ul>\n<li>The subject line should be 50 characters or less to prevent wrapping</li>\n<li>The subject line should be a statement written in <a href=\"https://www.grammarly.com/blog/imperative/\">imperative voice</a></li>\n<li>Add a commit message two carriage returns after the subject line</li>\n<li>Commit message lines should be limited to 72 characters</li>\n</ul>\n<p>And here’s an example commit following these guidelines:</p>\n<pre class=\"language-text\"><code class=\"language-text\">Add new awesome feature<br><br>Use this space for anything that needs further explanation. You can <br>add a list here as well:<br><br>- Added the thing<br>- Had to pull the other thing out into a separate module for reasons</code></pre>\n<p>It’s hard to know what your line character count is when staring into the black abyss of the terminal so you may want to change your default text editor to something you’re more comfortable with. I personally like to use VS Code as my editor:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">git</span> config --global core.editor <span class=\"token string\">\"code --wait\"</span></code></pre>\n<p>Running that command in your terminal should set up VS Code as the default git editor. The above command assumes you’re using git as your version control and have the <a href=\"https://code.visualstudio.com/docs/editor/command-line\">VS Code CLI</a> installed.</p>\n<h2 id=\"keep-it-short-and-sweet\" tabindex=\"-1\">Keep it short and sweet<a class=\"c-anchor-link\" href=\"#keep-it-short-and-sweet\" aria-label=\"permalink\" aria-describedby=\"keep-it-short-and-sweet\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I cannot tell you how many pull requests I’ve personally submitted with 20+ files changed and thousands of lines touched<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">[2]</a></sup>. If you’ve ever tried reviewing a PR like that, you’ll know how exhausting it is to simply <em>read</em> the entire thing, let alone reason about what’s going on.</p>\n<p>Pull requests should be kept short. If they can’t be kept short, use atomic commits and make sure to arrange your commits in a way that logically tells a story.</p>\n<p>Let’s imagine we need to add a new form to a project that uses existing logic. The commit history might look something like this:</p>\n<pre class=\"language-text\"><code class=\"language-text\">Reformat file to match standards<br>Refactor variable names for readability<br>Refactor form submission to extract logic<br>Add form markup<br>Style form<br>Share form logic with the new form</code></pre>\n<p>This history is arranged to tell a story. The beginning sets up the change with some reformatting and refactoring of existing files. The middle adds and styles the new form. Finally, the previous work is combined to complete the functionality.</p>\n<h2 id=\"review-and-clarify-if-necessary\" tabindex=\"-1\">Review and clarify if necessary<a class=\"c-anchor-link\" href=\"#review-and-clarify-if-necessary\" aria-label=\"permalink\" aria-describedby=\"review-and-clarify-if-necessary\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Your commits are atomic, you’ve followed the project’s standards, and you’ve arranged your commits in a logical order. The next step is to push your code up to the remote repository and review your pull request. I will usually save my pull request as <a href=\"https://github.blog/2019-02-14-introducing-draft-pull-requests/\">a draft on GitHub</a> at this stage.</p>\n<p>After posting a draft pull request, step through each commit, look through the changes, and ask yourself if any potential areas could cause a reviewer to get tripped up. I recommend taking a break before so you can have fresh eyes.</p>\n<p>If you find any trip hazards, add a comment to explain why you did what you did. If you can’t explain why you did what you did, this is a good time to say so and ask for any suggestions. These comments give reviewers much-needed context to help inform the review.</p>\n<h2 id=\"listen-to-the-reviewer\" tabindex=\"-1\">Listen to the reviewer<a class=\"c-anchor-link\" href=\"#listen-to-the-reviewer\" aria-label=\"permalink\" aria-describedby=\"listen-to-the-reviewer\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The final step to getting your pull request merged is listening to the reviewer. This can prove challenging sometimes, especially if the reviewer has difficulty communicating in a cordial manner (every team has that one dev…). Aim to receive and consider every comment with equal respect.</p>\n<p>Even if you disagree with the comment or request, there is always value in re-examining what you’ve written from someone else’s perspective. That doesn’t mean you should blindly do what the reviewer is suggesting. Sometimes it helps to get a second opinion.</p>\n<p>I have had to remind myself not to take each comment personally. In a discussion with <a href=\"https://twitter.com/chantastic?lang=en\">Chantastic</a> at a local meetup, he suggested to hold off replying to a review until you can start with “Thank you.” This will help put you in the right frame of mind when responding to a particularly harsh review.</p>\n<h2 id=\"in-summary-and-summation\" tabindex=\"-1\">In summary and summation<a class=\"c-anchor-link\" href=\"#in-summary-and-summation\" aria-label=\"permalink\" aria-describedby=\"in-summary-and-summation\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Creating helpful pull requests is a useful skill to develop, whether you’re contributing to a team or open source software. Creating atomic, standards-based commits in a reasonable order and taking the review process seriously will get you a long way to getting that new feature merged.</p>\n<p>If you’d like more information on how to make your pull requests the best they can be, check out the <a href=\"https://opensource.creativecommons.org/contributing-code/pr-guidelines/\">Creative Commons PR guidelines</a>. And if you found this post helpful, please let me know by liking it over on DEV Community, and follow <a href=\"https://twitter.com/therealboone\">me on Twitter</a> for random thoughts and occasional blog updates.</p>\n<p>Until next time!</p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>True story. Did you know there are 15 different <a href=\"https://www.worldstandards.eu/electricity/plugs-and-sockets/\">outlet plug design standards</a> in use throughout the world today? <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>Let me assure you karma is a <em>thing</em>. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-02-24T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/talk-to-your-react-components-with-custom-events/",
      "url": "https://www.falldowngoboone.com/blog/talk-to-your-react-components-with-custom-events/",
      "title": "Talk to your React components with custom events",
      "content_html": "<p>I build pages with both React and non-React components, and sometimes all these components need to talk to each other. Examples include opening a React modal when a customer clicks a button or updating a text block when a customer adds a product from a React stepper. There are many ways to do this, but in my opinion, the best way is to use <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent\">custom events</a>.</p>\n<h2 id=\"what-are-custom-events%3F\" tabindex=\"-1\">What are custom events?<a class=\"c-anchor-link\" href=\"#what-are-custom-events%3F\" aria-label=\"permalink\" aria-describedby=\"what-are-custom-events%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Custom events are just like regular browser events (e.g. “click”, “keyup”, etc.) except they’re manually created. You can create a simple synthetic event with a custom type using the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Event/Event\"><code>Event</code> constructor</a><sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">const</span> event <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Event</span><span class=\"token punctuation\">(</span><span class=\"token string\">'build'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>document<span class=\"token punctuation\">.</span><span class=\"token function\">dispatchEvent</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>If you need to pass arbitrary data, you can use the <code>CustomEvent</code> interface<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">[2]</a></sup>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">const</span> customEvent <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">CustomEvent</span><span class=\"token punctuation\">(</span><span class=\"token string\">'build'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">detail</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'primary'</span> <span class=\"token punctuation\">}</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>document<span class=\"token punctuation\">.</span><span class=\"token function\">dispatchEvent</span><span class=\"token punctuation\">(</span>customEvent<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>I use the <code>document</code> element as the single event handler for all custom events because it centralizes all event methods and decouples custom events from specific nodes on the page.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\">document<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'build'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> detail <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> name <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> detail<span class=\"token punctuation\">;</span><br>  <span class=\"token operator\">...</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Using a single entity to manage events makes this approach act like a browser-native <a href=\"https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern\">publish-subscribe pattern</a>. Benefits to this pattern include decoupling (previously mentioned) and scalability.</p>\n<h2 id=\"example-time!\" tabindex=\"-1\">Example time!<a class=\"c-anchor-link\" href=\"#example-time!\" aria-label=\"permalink\" aria-describedby=\"example-time!\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I’ve built an <a href=\"https://stackblitz.com/edit/react-zqp3ot?file=src%2FApp.js\">example app</a> with <a href=\"https://create-react-app.dev\">Create React App</a> to illustrate this. The <code>App</code> component includes a modal built with <a href=\"https://github.com/reactjs/react-modal\">React Modal</a>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// App.js</span><br><br><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">\"react\"</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> Modal <span class=\"token keyword\">from</span> <span class=\"token string\">\"react-modal\"</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token string\">\"./style.css\"</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>isOpen<span class=\"token punctuation\">,</span> setIsOpen<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">function</span> <span class=\"token function\">closeModal</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">setIsOpen</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br> <span class=\"token punctuation\">}</span><br><br> <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>   <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Trigger modal outside React</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Custom events are AWESOME!</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Modal</span></span> <span class=\"token attr-name\">isOpen</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>isOpen<span class=\"token punctuation\">}</span></span> <span class=\"token attr-name\">onRequestClose</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>closeModal<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">I was opened by a modal outside of React. How cool is that?</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>closeModal<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Close</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Modal</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>The <code>isOpen</code> prop determines the <code>Modal</code> component open state. We then control this state using the <code>useState</code> hook.</p>\n<p>We will create a button outside of the React component that opens the React app modal. Let’s add the button to the page:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- public/index.html --></span><br><br><span class=\"token comment\">&lt;!-- ... --></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>open-button<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>I'm outside React<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>root<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token comment\">&lt;!-- ... --></span></code></pre>\n<p>To make things a bit easier and reduce event boilerplate, I’ve put our event functions into a module:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// events.js</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">eventType<span class=\"token punctuation\">,</span> listener</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  document<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span>eventType<span class=\"token punctuation\">,</span> listener<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">off</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">eventType<span class=\"token punctuation\">,</span> listener</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  document<span class=\"token punctuation\">.</span><span class=\"token function\">removeEventListener</span><span class=\"token punctuation\">(</span>eventType<span class=\"token punctuation\">,</span> listener<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">once</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">eventType<span class=\"token punctuation\">,</span> listener</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token function\">on</span><span class=\"token punctuation\">(</span>eventType<span class=\"token punctuation\">,</span> handleEventOnce<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">function</span> <span class=\"token function\">handleEventOnce</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">listener</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token function\">off</span><span class=\"token punctuation\">(</span>eventType<span class=\"token punctuation\">,</span> handleEventOnce<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">trigger</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">eventType<span class=\"token punctuation\">,</span> data</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> event <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">CustomEvent</span><span class=\"token punctuation\">(</span>eventType<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">detail</span><span class=\"token operator\">:</span> data <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  document<span class=\"token punctuation\">.</span><span class=\"token function\">dispatchEvent</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">export</span> <span class=\"token punctuation\">{</span> on<span class=\"token punctuation\">,</span> once<span class=\"token punctuation\">,</span> off<span class=\"token punctuation\">,</span> trigger <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>You could go crazy and make this look more like traditional pub-sub implementations<sup class=\"footnote-ref\"><a href=\"#fn3\" id=\"fnref3\">[3]</a></sup>, or you could completely emulate the <a href=\"https://nodejs.org/api/events.html#events_class_eventemitter\"><code>EventEmitter</code></a> interface if you want. Here I’ve tried to capture the most common functions.</p>\n<p>Now that we have all the pieces in place we need to wire everything up.</p>\n<h2 id=\"putting-it-together\" tabindex=\"-1\">Putting it together<a class=\"c-anchor-link\" href=\"#putting-it-together\" aria-label=\"permalink\" aria-describedby=\"putting-it-together\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The next step is to publish an event when the open button is clicked. For this example app, I’m going to do that in the <code>index.js</code> file Create React App provides:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">\"react\"</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">\"react-dom\"</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> trigger <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"./events\"</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">import</span> App <span class=\"token keyword\">from</span> <span class=\"token string\">\"./App\"</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">const</span> openButton <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"open-button\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>openButton<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"click\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token function\">trigger</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"openButton:click\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>ReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">App</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token punctuation\">,</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"root\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>I’ve named the event <code>openButton:click</code>. I typically follow a pattern of <code>subject:verb</code>, mainly because that’s what I learned way back in my jQuery days. A nice benefit of this pattern is it reduces the possibility of event name collisions.</p>\n<p>Finally, we’ll listen for that event inside the <code>App</code> component and set the <code>isOpen</code> state to <code>true</code> when it’s triggered. Since adding event listeners is a side effect, we’ll use <code>useEffect</code> to do that.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">import</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">as</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">\"react\"</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> Modal <span class=\"token keyword\">from</span> <span class=\"token string\">\"react-modal\"</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> on<span class=\"token punctuation\">,</span> off <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"./events\"</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">import</span> <span class=\"token string\">\"./style.css\"</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>isOpen<span class=\"token punctuation\">,</span> setIsOpen<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">const</span> openModal <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setIsOpen</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  React<span class=\"token punctuation\">.</span><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"openButton:click\"</span><span class=\"token punctuation\">,</span> openModal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>      <span class=\"token function\">off</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"openButton:click\"</span><span class=\"token punctuation\">,</span> openModal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token punctuation\">}</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>openModal<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">function</span> <span class=\"token function\">closeModal</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">setIsOpen</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Trigger modal outside React</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Custom events are AWESOME!</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Modal</span></span> <span class=\"token attr-name\">isOpen</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>isOpen<span class=\"token punctuation\">}</span></span> <span class=\"token attr-name\">onRequestClose</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>closeModal<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">I was opened by a modal outside of React. How cool is that?</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>        </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span> <span class=\"token attr-name\">onClick</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>closeModal<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Close</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Modal</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>And now it works (hopefully)! You can <a href=\"https://stackblitz.com/edit/react-nwetpt?file=src/App.js\">test it for yourself over on StackBlitz</a>.</p>\n<p><strong>Update 2021-12-12</strong></p>\n<p>Many thanks to <a href=\"https://github.com/jpribyl\">Johnny Pribyl</a> for rightly pointing out that the <code>useEffect</code> needed a clean up function returned, otherwise a new listener would be added every single time the modal was rendered. <code>useEffect</code> also needs a dependency array to ensure it isn’t needlessly re-run. <code>openModal</code> <em>shouldn’t</em> change, but there’s always the possibility that a new dependency may be added to that <code>useCallback</code>.</p>\n<h2 id=\"custom-events-are-awesome-indeed\" tabindex=\"-1\">Custom events are awesome indeed<a class=\"c-anchor-link\" href=\"#custom-events-are-awesome-indeed\" aria-label=\"permalink\" aria-describedby=\"custom-events-are-awesome-indeed\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Custom events are great when you need two completely separate entities to talk to each other, which is a common problem in UI design. Be aware, though, this pattern’s not all sunshine and rainbows. Drawbacks include an increased difficulty of maintenance (ghost events, or published events that are no longer listened to) and a higher degree of reasoning (indeterminate order of execution).</p>\n<p>I hope I’ve at the very least piqued your interest in custom events, and maybe even given you a solution to a problem you’re dealing with right now. If that’s you, please do me a favor and like this article on DEV Community. And while you’re at it, <a href=\"https://twitter.com/therealboone\">follow me on Twitter</a> so I don’t get lonely.</p>\n<p>Until next time!</p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Note this code will not work in Internet Explorer (what does, amirite?). You will need to use the <a href=\"https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events#the_old-fashioned_way\">old-fashioned event constructor</a>. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>The <code>CustomEvent</code> constructor is also unsupported in Internet Explorer (whomp whomp). They are created the same way as <code>Event</code>s, but initialize with <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/initCustomEvent\"><code>initCustomEvent</code></a>. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn3\" class=\"footnote-item\"><p>One addition could be a method to remove all event listeners for a particular event. You would need to manually track listeners in an object since there’s no way of directly accessing event listeners in native browser event handling. <a href=\"#fnref3\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-02-23T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/tips-for-vanilla-javascript-dom-manipulation/",
      "url": "https://www.falldowngoboone.com/blog/tips-for-vanilla-javascript-dom-manipulation/",
      "title": "Tips for vanilla JavaScript DOM manipulation",
      "content_html": "<p>If you need to go <em>au naturale</em> with your JavaScript DOM manipulation, here are some tips for improving performance.</p>\n<h2 id=\"use-documentfragments-to-add-multiple-elements\" tabindex=\"-1\">Use <code>DocumentFragment</code>s to add multiple elements<a class=\"c-anchor-link\" href=\"#use-documentfragments-to-add-multiple-elements\" aria-label=\"permalink\" aria-describedby=\"use-documentfragments-to-add-multiple-elements\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Here’s one way you might add multiple DOM nodes to a mounted node:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">var</span> root <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fruit-list'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">var</span> fruitItems <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'apple'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'orange'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'banana'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">fruit</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">'li'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>\titem<span class=\"token punctuation\">.</span>innerText <span class=\"token operator\">=</span> fruit<span class=\"token punctuation\">;</span><br>\t<span class=\"token keyword\">return</span> item<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">var</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> fruitItems<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\troot<span class=\"token punctuation\">.</span><span class=\"token function\">appendChild</span><span class=\"token punctuation\">(</span>fruitItems<span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// page reflows every time</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>This code works, but the issue is the page will reflow every time <code>appendChild</code> is called. If you have a long list of items to add, you’re going to end up in a serious performance bottleneck, and an unhappy boss. The solution is to use a <code>[DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment)</code>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">var</span> root <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fruit-list'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">var</span> fragment <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">crateDocumentFragment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">var</span> fruitItems <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'apple'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'orange'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'banana'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">fruit</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">'li'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>\titem<span class=\"token punctuation\">.</span>innerText <span class=\"token operator\">=</span> fruit<span class=\"token punctuation\">;</span><br>\t<span class=\"token keyword\">return</span> item<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">var</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> fruitItems<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\tfragment<span class=\"token punctuation\">.</span><span class=\"token function\">appendChild</span><span class=\"token punctuation\">(</span>fruitItems<span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// no page reflow!</span><br><span class=\"token punctuation\">}</span><br><br>root<span class=\"token punctuation\">.</span><span class=\"token function\">appendChild</span><span class=\"token punctuation\">(</span>fragment<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>The <code>appendChild</code> method is only called once, and this makes browsers (and my boss) very happy.</p>\n<h2 id=\"but-if-you-can%2C-use-parentnode.append\" tabindex=\"-1\">But if you can, use <code>ParentNode.append</code><a class=\"c-anchor-link\" href=\"#but-if-you-can%2C-use-parentnode.append\" aria-label=\"permalink\" aria-describedby=\"but-if-you-can%2C-use-parentnode.append\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>You can think of the <code>[ParentNode.append](https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append)</code> method as <code>appendChild</code> on steroids (sans the rage and adult acne). Unlike its puny cousin <code>appendChild</code>, <code>append</code> can take multiple nodes, automatically converts string arguments to text nodes, and it utilizes <code>DocumentFragment</code> for us:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// the `consts` are my way of letting you know this is newer...🙃</span><br><br><span class=\"token keyword\">const</span> root <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fruit-list'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> fragment <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">crateDocumentFragment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> fruitItems <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'apple'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'orange'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'banana'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">fruit</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token keyword\">const</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">'li'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>\titem<span class=\"token punctuation\">.</span>innerText <span class=\"token operator\">=</span> fruit<span class=\"token punctuation\">;</span><br>\t<span class=\"token keyword\">return</span> item<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>root<span class=\"token punctuation\">.</span><span class=\"token function\">append</span><span class=\"token punctuation\">(</span><span class=\"token operator\">...</span>fruitItems<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This is the most convenient way to add multiple nodes to a parent node. <a href=\"https://caniuse.com/mdn-api_element_append\">Support is great</a> if you don’t have to prop up Internet Explorer. Luckily, if you do, there’s a <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append#polyfill\">polyfill</a> for that.</p>\n<h2 id=\"create-documentfragments-from-strings-with-ranges\" tabindex=\"-1\">Create <code>DocumentFragment</code>s from strings with <code>Range</code>s<a class=\"c-anchor-link\" href=\"#create-documentfragments-from-strings-with-ranges\" aria-label=\"permalink\" aria-describedby=\"create-documentfragments-from-strings-with-ranges\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Imagine a world where you want to create HTML from a string. You might do something like this:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// orange you getting tired of this example yet?</span><br><br><span class=\"token keyword\">const</span> root <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fruit-list'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>root<span class=\"token punctuation\">.</span>innerHTML <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"><br>\t&lt;li>apple&lt;/li><br>\t&lt;li>orange&lt;/li><br>\t&lt;li>banana&lt;/li><br></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span></code></pre>\n<p>This is nice if you’re trying to recreate JSX, but it’s not as performant as using <code>DocumentFragment</code>s. Luckily there’s a way to directly create a <code>DocumentFragment</code> from a string. Contrived code warning:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">const</span> root <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fruit-list'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">const</span> fragment <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createRange</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">createContextualFragment</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\"><br>\t&lt;li>apple&lt;/li><br>\t&lt;li>orange&lt;/li><br>\t&lt;li>banana&lt;/li><br></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br>root<span class=\"token punctuation\">.</span><span class=\"token function\">appendChild</span><span class=\"token punctuation\">(</span>fragment<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>The <code>createRange</code> method returns a <code>Range</code>, which is a representation of a sliver of the current DOM document. The <code>createContextualFragment</code> creates a <code>DocumentFragment</code> using a parsing algorithm based on the current document’s context (in this case, HTML). <code>Range</code> methods are meant to be convenience methods built on top of common node editing patterns with optimization in mind, and I’m quite interested to learn more about them.</p>\n<h2 id=\"memorize-the-dom-properties-that-trigger-layout\" tabindex=\"-1\">Memorize the DOM properties that trigger layout<a class=\"c-anchor-link\" href=\"#memorize-the-dom-properties-that-trigger-layout\" aria-label=\"permalink\" aria-describedby=\"memorize-the-dom-properties-that-trigger-layout\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The DOM API is tricky because just observing certain node properties can trigger page layout. Doing this multiple times in a row can be a performance problem. Doing this inside a loop can cause <a href=\"https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing\">layout thrashing</a> (trust me, it’s as bad as it sounds).</p>\n<p>You’ll want to be aware of what DOM properties cause the browser to trigger layout, so you need to get to memorizing. Or you could simply bookmark this convenient <a href=\"https://gist.github.com/paulirish/5d52fb081b3570c81e3a\">list of properties that cause layout</a>.</p>\n<h2 id=\"this-is-only-scratching-the-proverbial-surface\" tabindex=\"-1\">This is only scratching the proverbial surface<a class=\"c-anchor-link\" href=\"#this-is-only-scratching-the-proverbial-surface\" aria-label=\"permalink\" aria-describedby=\"this-is-only-scratching-the-proverbial-surface\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>There’s more to DOM layout with vanilla JavaScript, to be sure. I’m interested in looking at some of the performance optimizations VDOM libraries employ to eek the most out of DOM manipulation. I kinda like that sort of thing.</p>\n<p>I hope you learned something new today. And if you did, please consider liking this post on DEV Community, and let me know on Twitter. I get lonely sometimes.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-02-22T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/11-podcasts-for-the-frontend-developer/",
      "url": "https://www.falldowngoboone.com/blog/11-podcasts-for-the-frontend-developer/",
      "title": "11 podcasts for the frontend developer",
      "content_html": "<p>I’m a huge fan of continuing education, and one of the ways I binge on information is through podcasts. Here’s a list of 11 podcasts that I find not only educational but entertaining as well.</p>\n<ul>\n<li><a href=\"https://changelog.com/jsparty\">JS Party</a> - From the folks at Changelog, this weekly, hour-ish podcast focusing on JavaScript features a rotating panel and format.</li>\n<li><a href=\"https://frontendhappyhour.com\">Front End Happy Hour</a> - A bunch of developers drinking and talking about development. What could go wrong?</li>\n<li><a href=\"https://spec.fm/podcasts/developer-tea\">Developer Tea</a> - This podcast is more about the human element of development. I recommend this to developers of all levels, but especially beginners.</li>\n<li><a href=\"https://fsjam.org\">FSJam Podcast</a> - Fullstack Jamstack conversations with developers, library maintainers, and industry thought leaders.</li>\n<li><a href=\"https://99percentinvisible.org\">99% Invisible</a> - It’s not all dev-centric podcasts here. <em>99% Invisible</em> peels back the curtain on the design of everyday things. <a href=\"https://99percentinvisible.org/episode/episode-06-99-symbolic/\">The flag episode</a> is a classic.</li>\n<li><a href=\"https://fullstackradio.com\">Full Stack Radio</a> - Adam Wathan, creator of (among other things) Tailwind, hosts this podcast with a focus on all the things happening on the front end.</li>\n<li><a href=\"https://hiddenbrain.org\">Hidden Brain</a> - This fascinating podcast delves into why we do the things we do and how we can learn from that. It’s honestly one of my favs.</li>\n<li><a href=\"https://reactpodcast.com\">React Podcast</a> - It’s about React. So…</li>\n<li><a href=\"https://shoptalkshow.com\">ShopTalk Show</a> - Chris Coyier (<a href=\"https://css-tricks.com\">CSS-Tricks</a>) and Dave Rupert (<a href=\"https://paravelinc.com\">Paravel</a>) host this quirky podcast (mostly) about frontend. This podcast was my first developer podcast ever and still one of my favorites.</li>\n<li><a href=\"https://syntax.fm\">Syntax</a> - Hosted by Wes Bos and Scott Tolinski, I highly recommend this podcast if you are new to JavaScript. It’s chock-full of tips and sick picks.</li>\n<li><a href=\"https://freakonomics.com/archive/\">Freakonomics Radio</a> - Again, a podcast about humans for humans. This one has a strong focus on Behavioral Economics, the cross-section of psychology and econ.</li>\n</ul>\n<p>Don’t see your favorite here? <a href=\"https://twitter.com/therealboone\">Let me know on Twitter</a>. And if you found this post helpful, please let me know by liking it on DEV Community.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-02-21T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/what-is-your-code-communicating/",
      "url": "https://www.falldowngoboone.com/blog/what-is-your-code-communicating/",
      "title": "What is your code communicating?",
      "content_html": "<p>Developers don’t write code for computers. I mean, we do, but not primarily. If we did, it would make no difference whether we wrote in Java, bytecode, or complete binary. Yet when given a choice, we write in abstractions because <strong>developers write code for other developers.</strong></p>\n<h2 id=\"the-why%3F-behind-the-what%3F\" tabindex=\"-1\">The <em>Why?</em> behind the <em>What?</em><a class=\"c-anchor-link\" href=\"#the-why%3F-behind-the-what%3F\" aria-label=\"permalink\" aria-describedby=\"the-why%3F-behind-the-what%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Knowing this, you should always strive to lean into the abstraction and communicate why your code exists <em>in the code itself.</em> That is how you make self-documenting code<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">[1]</a></sup>.</p>\n<p>Let’s look at an example in <a href=\"https://sass-lang.com\">Sass</a>. If you’re unfamiliar with Sass, it’s a preprocessor scripting language that compiles to CSS. It’s a further abstraction of CSS built to make CSS more expressive.</p>\n<p>Imagine you come across this style in a code review:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.subheading-2 </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">font-size</span><span class=\"token punctuation\">:</span> 1.5rem<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">font-weight</span><span class=\"token punctuation\">:</span> bold<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">line-height</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">margin-top</span><span class=\"token punctuation\">:</span> 20 <span class=\"token operator\">/</span> 24 <span class=\"token operator\">*</span> 1em<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Does anything jump out? You might ask why <code>margin-top</code> has an equation value (honestly, I’d prefer not to include a margin in this type of style; if you want to find out why <a href=\"https://twitter.com/therealboone\">reach out to me on Twitter</a>).</p>\n<p>You can probably figure out what that line is doing, but it’s an unnecessary speed bump in the middle of an otherwise unremarkable piece of code. And as any good editor knows, anything that unnecessarily slows a reader down needs to be eliminated.</p>\n<h2 id=\"making-the-abstraction-literally-literal\" tabindex=\"-1\">Making the abstraction literally literal<a class=\"c-anchor-link\" href=\"#making-the-abstraction-literally-literal\" aria-label=\"permalink\" aria-describedby=\"making-the-abstraction-literally-literal\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Let’s try making that <code>margin-top</code> a bit more readable:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.subheading-2 </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">font-size</span><span class=\"token punctuation\">:</span> 1.5rem<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">font-weight</span><span class=\"token punctuation\">:</span> bold<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">line-height</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">margin-top</span><span class=\"token punctuation\">:</span> 0.8em<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>You are less likely to get any questions about that. But I’m still bothered by one thing: <code>0.8em</code> is a rather arbitrary value, and <code>em</code> units tend to be confusing, especially if you work on a team of developers that aren’t CSS-savvy.</p>\n<p>What I want to do is communicate that, at the effective font size of <code>24px</code> (<code>1.5rem</code>), the <code>margin-top</code> should be <code>20px</code>. You might be tempted to communicate this in a comment, which is easy to do in Sass:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.subheading-2 </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">font-size</span><span class=\"token punctuation\">:</span> 1.5rem<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">font-weight</span><span class=\"token punctuation\">:</span> bold<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">line-height</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">margin-top</span><span class=\"token punctuation\">:</span> 0.8em<span class=\"token punctuation\">;</span> <span class=\"token comment\">// 20px in ems</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>That certainly communicates what we’re trying to do, but comments like this one are tightly coupled to the code, meaning if the code changes, the comment needs to change as well. This could (and inevitably will) lead to stale comments.</p>\n<h2 id=\"back-to-the-land-of-abstraction\" tabindex=\"-1\">Back to the land of abstraction<a class=\"c-anchor-link\" href=\"#back-to-the-land-of-abstraction\" aria-label=\"permalink\" aria-describedby=\"back-to-the-land-of-abstraction\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you find yourself writing comments like this, a good rule of thumb is to use the comments as a template for abstraction<sup class=\"footnote-ref\"><a href=\"#fn2\" id=\"fnref2\">[2]</a></sup>. Luckily for us, Sass gives us the ability to <a href=\"https://sass-lang.com/documentation/at-rules/function\">abstract this meaning into functions</a>. A bit of searching on the interwebs leads me to a useful <a href=\"https://css-tricks.com/snippets/sass/px-to-em-functions/\">function to turn pixel values into em units</a>.</p>\n<p>Let’s incorporate our new <code>em</code> function into our style:</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.subheading-2 </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">font-size</span><span class=\"token punctuation\">:</span> <span class=\"token function\">rem</span><span class=\"token punctuation\">(</span><span class=\"token property\"><span class=\"token variable\">$px</span></span><span class=\"token punctuation\">:</span> 24<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">font-weight</span><span class=\"token punctuation\">:</span> bold<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">line-height</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">margin-top</span><span class=\"token punctuation\">:</span> <span class=\"token function\">em</span><span class=\"token punctuation\">(</span><span class=\"token property\"><span class=\"token variable\">$px</span></span><span class=\"token punctuation\">:</span> 20<span class=\"token punctuation\">,</span> <span class=\"token property\"><span class=\"token variable\">$context</span></span><span class=\"token punctuation\">:</span> 24<span class=\"token punctuation\">)</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Hey, look, I wrote a <code>rem</code> function, too! I would argue this better fits a developer’s mental model when translating <a href=\"https://www.uxbeginner.com/glossary/redlining/\">redline documents</a> into code. No math, and no confusion around what <code>em</code>’s context is.</p>\n<h2 id=\"how-to-find-opportunities-for-improved-communication\" tabindex=\"-1\">How to find opportunities for improved communication<a class=\"c-anchor-link\" href=\"#how-to-find-opportunities-for-improved-communication\" aria-label=\"permalink\" aria-describedby=\"how-to-find-opportunities-for-improved-communication\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you are writing the code, often you know too much about what you are doing to reliably recognize confusing lines. Use code reviews to help with this. A good reviewer will always ask questions, and these questions can help identify opportunities for abstraction<sup class=\"footnote-ref\"><a href=\"#fn3\" id=\"fnref3\">[3]</a></sup>.</p>\n<p>Even if you get a terrible code review fraught with nitpicks and complete rewrites (and apologies if you do), there is still some meaningful feedback you can take away. You can see where other developers get tripped up, allowing you to better identify problem areas<sup class=\"footnote-ref\"><a href=\"#fn4\" id=\"fnref4\">[4]</a></sup>.</p>\n<h2 id=\"communication-is-everywhere\" tabindex=\"-1\">Communication is everywhere<a class=\"c-anchor-link\" href=\"#communication-is-everywhere\" aria-label=\"permalink\" aria-describedby=\"communication-is-everywhere\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Your code is always communicating something, and it’s your job as a developer to make sure it’s communicating the right thing. This not only applies to Sass but to every coding language in existence, from HTML to Rust to whatever hot language the future gives us. Look for confusing lines of code, ask yourself why it exists, and lift that context into an abstraction.</p>\n<p>If you can’t tell, this is one of those subjects that I love. If you’d like to hear more about how to better communicate through code, please let me know by liking this article on DEV Community and sharing it with others. Also consider following <a href=\"https://twitter.com/therealboone\">me on Twitter</a>, especially if you like rage tweets about local infrastructure and random tomfoolery.</p>\n<p>One last note: I learned this idea of code as communication from Jonathan Cutrell’s amazing podcast <a href=\"https://spec.fm/podcasts/developer-tea\">Developer Tea</a>. Whether you’re a beginner or a seasoned pro, I highly recommend subscribing to this podcast. It focuses on the human side of development, a topic that is often ignored.</p>\n<p>Until my next communication!</p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>There’s been some confusion over the meaning of the term <em>self-documenting code,</em> but my definition is code that’s readable and reasonable to other human beings. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>This is a technique that I learned from Martin Fowler’s excellent book <em><a href=\"https://martinfowler.com/books/refactoring.html\">Refactoring</a></em>. <a href=\"#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn3\" class=\"footnote-item\"><p>The example in this post came from a real code review on my team. <a href=\"#fnref3\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn4\" class=\"footnote-item\"><p>Of course, if someone is a terrible code reviewer, not all of their feedback is going to point to actual problems. You’ll have to use your best judgment here, but it’s at least worth reassessing your choices. <a href=\"#fnref4\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2021-02-20T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/how-to-avoid-premature-abstractions-in-react/",
      "url": "https://www.falldowngoboone.com/blog/how-to-avoid-premature-abstractions-in-react/",
      "title": "How to avoid premature abstractions in React",
      "content_html": "<p>As a junior developer, my number one problem was creating premature abstractions. Nowhere was this more evident than my React components.</p>\n<h2 id=\"it-started-with-an-input\" tabindex=\"-1\">It started with an input<a class=\"c-anchor-link\" href=\"#it-started-with-an-input\" aria-label=\"permalink\" aria-describedby=\"it-started-with-an-input\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I worked on a large project involving several form elements, so as part of bootstrapping on top of Create React App, I created some form components that wrapped around <a href=\"https://formik.org/\">Formik</a>. Here’s what the <code>Input</code> element looked like in use:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Input</span></span> <span class=\"token attr-name\">label</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Full Name<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>username<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>username<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span></code></pre>\n<p>The <code>label</code>, <code>name</code>, and <code>id</code> were all required, which was something I thought was clever to ensure proper input labeling. This component also automatically tied into Formik’s form validation and dynamically generated field errors when data was invalid.</p>\n<h2 id=\"then-the-tooltips-showed-up\" tabindex=\"-1\">Then the tooltips showed up<a class=\"c-anchor-link\" href=\"#then-the-tooltips-showed-up\" aria-label=\"permalink\" aria-describedby=\"then-the-tooltips-showed-up\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I had abstracted away all the complexity into a simple, useful API. I thought this was all we would need. But then a new design came through that required a tooltip to render inline with an input label.</p>\n<p>I wanted to keep the interface simple, so I added a <code>tooltip</code> component set to a string, which would become the child element of a <code>Tooltip</code> component alongside the label.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Input</span></span> <br>  <span class=\"token attr-name\">label</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Cell Phone<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">tooltip</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>This is required for receiving texts.<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>phone<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>phone<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>tel<span class=\"token punctuation\">\"</span></span><br><span class=\"token punctuation\">/></span></span></code></pre>\n<p>Not that great, but it still looks manageable. But the variations kept coming. Some inputs needed a visible message. Others needed a special icon by the label.</p>\n<h2 id=\"enter-render-props\" tabindex=\"-1\">Enter render props<a class=\"c-anchor-link\" href=\"#enter-render-props\" aria-label=\"permalink\" aria-describedby=\"enter-render-props\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I decided the best way to handle all these use cases was to extend the <code>label</code> prop to receive <a href=\"https://reactjs.org/docs/render-props.html\">render props</a>:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Input</span></span> <br>  <span class=\"token attr-name\">label</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>Label<span class=\"token punctuation\">,</span> labelProps<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Label</span></span> <span class=\"token spread\"><span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>labelProps<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Cell Phone</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Label</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span><span class=\"token string\">\" \"</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Tooltip</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">This is required for receiving texts.</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Tooltip</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Cell phones are great, right?</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><br>  <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>phone<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>phone<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>tel<span class=\"token punctuation\">\"</span></span><br><span class=\"token punctuation\">/></span></span></code></pre>\n<p>Okay, not as simple as what we started with, but <em>probably</em> maintainable? Then I got even more variations in, this time around the input itself. Designs were calling for an inline icon, a separate button, dynamic images…so I made the input itself a render prop.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Input</span></span> <br>  <span class=\"token attr-name\">label</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>Label<span class=\"token punctuation\">,</span> labelProps<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Label</span></span> <span class=\"token spread\"><span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>labelProps<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Cell Phone</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Label</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span><span class=\"token string\">\" \"</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Tooltip</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">This is required for receiving texts.</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Tooltip</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Cell phones are great, right?</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><br>  <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>phone<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>phone<span class=\"token punctuation\">\"</span></span><br>  <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>tel<span class=\"token punctuation\">\"</span></span><br><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>Input<span class=\"token punctuation\">,</span> inputProps<span class=\"token punctuation\">,</span> InputGroup<span class=\"token punctuation\">,</span> inputGroupProps<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">InputGroup</span></span> <span class=\"token spread\"><span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>inputGroupProps<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Input</span></span> <span class=\"token spread\"><span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>inputGroupProps<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">IconButton</span></span> <span class=\"token attr-name\">variant</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>phone<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"><br>  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">InputGroup</span></span><span class=\"token punctuation\">></span></span><br><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Input</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<p>I get panic sweats just looking at that. What is it? Why are there two types of <code>Input</code>? And what is the flow of props? This is not maintainable; it’s barely readable, especially when surrounded by more of these monstrosities!</p>\n<p>The example above is a small sample of the horror show this component became. It also had support for checkboxes and buttons. And as terrible as the API looked, the component’s code looked indecipherable. I’m not posting it here for fear of losing my developer card.</p>\n<h2 id=\"walking-back-the-design\" tabindex=\"-1\">Walking back the design<a class=\"c-anchor-link\" href=\"#walking-back-the-design\" aria-label=\"permalink\" aria-describedby=\"walking-back-the-design\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If I had to do it all over again, I would’ve put off making a shared input component. Isolating components allows more real-world use cases to organically develop, leading to a better-informed API.</p>\n<p>I’ve since realized it’s much better to break up components into their atomic parts, which allows for more flexibility and composability. What do I mean by atomic? Something like this:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Field</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>username<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Label</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\">Full Name</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Label</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">TextInput</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"><br>  </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">FieldMessage</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"><br></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Field</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<p>I’ve pulled all the field data out into a <code>Field</code> component, which uses context to build and pass all the necessary information into its children. The children themselves can either utilize the data passed in via a custom <code>useField</code> hook, or fallback to explicit props.</p>\n<p>Granted, it’s not as elegant as the original, But it’s more composable. I can now easily rearrange the elements of the input field without render prop soup (e.g., move the <code>FieldMessage</code> above the <code>TextInput</code>). And by using dynamically generated IDs and context, I can forgo the requirement of an explicit ID as well.</p>\n<p>The only downside to this is requiring a label becomes trickier. I could probably work out a solution by expecting a label ref to be passed through context, or I could just leave it and see if it’s a real problem to be solved.</p>\n<p>And if you still want that nice, elegant API from the very beginning, you could do something like this:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">TextField</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">,</span> label<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Field</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span>(name)</span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Label</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>label<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Label</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">TextInput</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">FieldMessage</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Field</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// &lt;TextField label=\"Full Name\" name=\"username\" /></span></code></pre>\n<h2 id=\"how-to-avoid-this\" tabindex=\"-1\">How to avoid this<a class=\"c-anchor-link\" href=\"#how-to-avoid-this\" aria-label=\"permalink\" aria-describedby=\"how-to-avoid-this\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The answer to avoiding premature abstraction is simple: don’t create abstractions until there is a need. Need is a relative term, but a good, solid rule to follow is don’t abstract duplicated code until you have found at least three instances of duplication. This is known as <a href=\"https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)\">the Rule of Three</a>.</p>\n<p>In React, components are abstractions, so you should hold off <em>sharing</em> a component until there are similar components in three different places. Note that you can, and should, still create private components. It’s a great way to keep duplicated code visible, as well as good practice for fine-tuning the component’s API.</p>\n<h2 id=\"what-now%3F\" tabindex=\"-1\">What now?<a class=\"c-anchor-link\" href=\"#what-now%3F\" aria-label=\"permalink\" aria-describedby=\"what-now%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you’d like to learn more about the dangers of premature abstraction, I highly recommend watching Dan Abramov’s <em><a href=\"https://www.deconstructconf.com/2019/dan-abramov-the-wet-codebase\">The Wet Codebase</a></em> talk from Deconstruct 2019. And if you liked this article, please consider liking it on Dev Community, and follow me on Twitter to receive updates.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-02-19T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/12-newsletters-for-frontend-developers/",
      "url": "https://www.falldowngoboone.com/blog/12-newsletters-for-frontend-developers/",
      "title": "12 newsletters for frontend developers",
      "content_html": "<p>Frontend development is a field that changes daily, and to stay up-to-date, I need a steady source of new information. One way I do this is through newsletters.</p>\n<p>Here’s a list of some of the newsletters I subscribe to for all the latest frontend news:</p>\n<ul>\n<li><a href=\"https://react.statuscode.com\">React Status</a> - For, you know, React stuff.</li>\n<li><a href=\"https://csslayout.news\">CSS Layout News</a> - <a href=\"https://rachelandrew.co.uk\">Rachel Andrew</a> maintains this newsletter about CSS layout.</li>\n<li><a href=\"https://www.smashingmagazine.com/the-smashing-newsletter/\">Smashing Magazine</a> - From the brilliant people at <a href=\"https://www.smashingmagazine.com\">Smashing Magazine</a>, of course.</li>\n<li><a href=\"http://news.design.systems\">Design Systems News</a> - Great information on creating and maintaining successful design systems.</li>\n<li><a href=\"https://css-tricks.com/newsletter/238-responsible-web-applications/\">CSS-Tricks Newsletter</a> - Weekly newsletter from the <a href=\"https://css-tricks.com\">CSS-Tricks</a> team.</li>\n<li><a href=\"https://javascriptweekly.com\">JavaScript Weekly</a> - All the JavaScript you can handle.</li>\n<li><a href=\"https://nodeweekly.com\">Node Weekly</a> - Even more JavaScript, this time focusing on Node.js.</li>\n<li><a href=\"https://screenlane.com/subscribe/\">Screenlane</a> - Interesting UI animation examples and tutorials.</li>\n<li><a href=\"https://responsivedesign.is/newsletter/\">RWD Weekly</a> - I know it says Responsive Web Design, but it’s a good source for general frontend dev information.</li>\n<li><a href=\"https://frontendfoc.us\">Frontend Focus</a> - Focuses on frontend, oddly enough.</li>\n<li><a href=\"https://jamstack.email\">JAMstacked</a> - You know I gotta have that JAMstack info.</li>\n<li><a href=\"https://webaim.org/newsletter/\">WebAIM Newsletter</a> - Get the latest information regarding <a href=\"https://webaim.org\">WebAIM</a> and accessibility on the web.</li>\n</ul>\n<p>Do you have a favorite newsletter? I would be forever grateful if you <a href=\"https://twitter.com/therealboone\">tell me all about it</a>. And if you liked this list, check out this <a href=\"https://www.falldowngoboone.com/blog/10-interesting-books-for-developers/\">list of books for developers</a> I just wrote about.</p>\n",
      "date_published": "2021-02-18T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/description-lists-are-awesome/",
      "url": "https://www.falldowngoboone.com/blog/description-lists-are-awesome/",
      "title": "Description lists are awesome",
      "content_html": "<p>The <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl\">description list</a> (<code>&lt;dl&gt;</code>) is a magical element that can be used to mark up anything from dictionary entries to recipes. So, what’s so special about it?</p>\n<h2 id=\"it%E2%80%99s-all-relational\" tabindex=\"-1\">It’s all relational<a class=\"c-anchor-link\" href=\"#it%E2%80%99s-all-relational\" aria-label=\"permalink\" aria-describedby=\"it%E2%80%99s-all-relational\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The description list, like its cousins the ordered and unordered list, is a list of associated items, meaning all items should be considered related to each other. The big difference is description list items are made up of two parts, a term (<code>&lt;dt&gt;</code>) and description (<code>&lt;dd&gt;</code>).</p>\n<p>Here’s what that looks like:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dl</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Freshly Brewed Coffee<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>$1.75<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Iced Coffee<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>$2.25<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Caffé Americano<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>$2.25<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Flat White<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>$3.75<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dl</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Notice that, unlike ordered and unordered lists, you can wrap related terms and descriptions in a single <code>div</code> to aid with styling. Normally a <code>div</code> would indicate a semantic separation of content, but inside a <code>&lt;dl&gt;</code> it’s completely ignored.</p>\n<p>And just like an ordered list, the order of the terms may be significant as well:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dl</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>If product pricing is hidden<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Show \"See price in cart\"<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>If product is on sale<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Show sale pricing and styling<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Otherwise<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Show regular pricing and styling<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dl</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>That some pretty mind-blowing stuff, right? Okay, it’s not life-changing, but the description list is perfect for semantically establishing a relationship between terms and descriptions.</p>\n<h2 id=\"what-are-they-good-for%3F\" tabindex=\"-1\">What are they good for?<a class=\"c-anchor-link\" href=\"#what-are-they-good-for%3F\" aria-label=\"permalink\" aria-describedby=\"what-are-they-good-for%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So, when would you reach for the description list? Well, I work in e-commerce, so the first thing I can think of is product metadata on a product detail page:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dl</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Price:<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>$29.99<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>SKU:<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>123456<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Colors:<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Red<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Green<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Blue<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Features:<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Non-slip finish<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Dishwasher safe<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>Microwave safe<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>One size fits most pots and pans<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dl</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Note that you can have multiple descriptions relating to a single term. I’ve seen this type of information marked up as a <code>table</code> and as separate <code>div</code>s, but this is semantically more correct.</p>\n<p>Another use of description lists that I’ve seen is in recipes:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dl</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Ingredients<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>flour<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>salt<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>dry yeast<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>sugar<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span>...<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dt</span><span class=\"token punctuation\">></span></span>Instructions<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dt</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dd</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>Mix all dry ingredients in a bowl. Add wet ingredients.<br>    Let stand for 2 hours.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>Preheat oven to 375°.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>...<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dd</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dl</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>The description list is useful in any situation where you have a list of related things that need to be broken down into name-value pairs. I even found a great <a href=\"http://maxdesign.com.au/articles/definition/\">article that suggests several more uses</a>, all the way from the distant year 2004.</p>\n<h2 id=\"gotchas\" tabindex=\"-1\">Gotchas<a class=\"c-anchor-link\" href=\"#gotchas\" aria-label=\"permalink\" aria-describedby=\"gotchas\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Even though the description list has been around since 1993, iOS VoiceOver has lacked proper support since it was first introduced in 2009. However, VoiceOver on iOS 14 and iPadOS 14 finally support description lists. As <a href=\"https://adrianroselli.com/2020/09/voiceover-on-ios-14-supports-description-lists.html\">Adrian Roselli writes in a recent article</a>, however, it is not without its quirks, mostly owed to existing VoiceOver bugs.</p>\n<h2 id=\"the-underutilized-list\" tabindex=\"-1\">The underutilized list<a class=\"c-anchor-link\" href=\"#the-underutilized-list\" aria-label=\"permalink\" aria-describedby=\"the-underutilized-list\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Description lists are great for groups of name-value pairs, which covers a surprising amount of semantic content. Next time you’re marking up your HTMLs and whatnot, consider the humble description list.</p>\n<p>Are you already using description lists? <a href=\"https://twitter.com/therealboone\">Let me know</a> what you’re using them for. And if you’re reading this on Dev Community, please consider liking this post if it is in any way helpful. This helps me know what articles make the most impact.</p>\n<p>Until tomorrow!</p>\n",
      "date_published": "2021-02-16T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/10-interesting-books-for-developers/",
      "url": "https://www.falldowngoboone.com/blog/10-interesting-books-for-developers/",
      "title": "10 interesting books for developers",
      "content_html": "<p>Reading is a great way to learn, but it’s also a fantastic way to open yourself up to new ideas and experiences. As a developer, I believe reading is important to my continued growth and advancement. If you believe that too, you might enjoy these ten books that I find particularly interesting.</p>\n<ul>\n<li>\n<p><em>Eloquent JavaScript</em>, Marijn Haverbeke</p>\n<p>This is the book that taught me JavaScript. I found it incredibly approachable, and it can be read <a href=\"https://eloquentjavascript.net\">online for free</a>, though I do recommend buying it if you can.</p>\n</li>\n<li>\n<p><em>Atomic Habits: An Easy &amp; Proven Way to Build Good Habits &amp; Break Bad Ones</em>, James Clear</p>\n<p>Clear’s main idea is that habits are more powerful than goals, and this book offers practical advice and techniques to build systems to support (or even stop) habits.</p>\n</li>\n<li>\n<p><em>The Willpower Instinct: How Self-Control Works, Why It Matters, and What You Can Do to Get More of It</em>, Kelly McGonigal</p>\n<p>Kelly McGonigal is a Stanford University psychologist that teaches classes on willpower. This book is a glimpse into her curriculum. If you are curious about what the latest research says about willpower and how to increase it, this book is a must-read.</p>\n</li>\n<li>\n<p><em>Pragmatic Thinking and Learning: Refactor Your Wetware</em>, Andy Hunt</p>\n<p>The first of two Pragmatic Programmer books on this list. This book provides a framework for how to think and grow as a developer.</p>\n</li>\n<li>\n<p><em>The Pragmatic Programmer: Your Journey To Mastery</em>, Dave Thomas and Andy Hunt</p>\n<p>This is the other Pragmatic Programmer book. I believe this book should be required reading for all developers. Some of the concepts in this book have helped shaped my mental model of code and have helped me grow in my ability to communicate effectively with code. I recommend the new 20th-anniversary edition.</p>\n</li>\n<li>\n<p><em>Refactoring: Improving the Design of Existing Code</em>, Martin Fowler</p>\n<p><em>Refactoring</em> is a book I reference continually as a guiding source for making code more readable. The second edition has been completely retooled, with JavaScript replacing Java as the example language, something I very much appreciate.</p>\n</li>\n<li>\n<p><em>The Elements of Typographic Style</em>, Robert Bringhurst</p>\n<p>I have an obsession with typography, and this book is something of a typographer’s bible. Most of the internet is typography, so this is probably a good thing to have in your back pocket.</p>\n</li>\n<li>\n<p><em>The Illusion of Life: Disney Animation</em>, Frank Thomas and Ollie Johnston</p>\n<p>The stories alone make this book a worthy addition to anyone’s library. The bonus is learning important animation fundamentals that will inform your UI and help you communicate with designers.</p>\n</li>\n<li>\n<p><em>The Design of Everyday Things</em>, Don Norman</p>\n<p>Don Norman, one of the founders of the <a href=\"https://www.nngroup.com\">Nielsen Norman Group</a>, pioneered much of modern User Experience Design. This book dives into Norman’s thinking process, and will forever change how you look at department store doors.</p>\n</li>\n<li>\n<p><em>Thinking, Fast and Slow</em>, Daniel Kahneman</p>\n<p>This book marries psychology and economics to create a new framework for looking at both fields. It sparked my imagination and began my interest in behavioral economics, and is probably the most fascinating book I’ve ever read.</p>\n</li>\n</ul>\n<p>I hope that you find these books as interesting as I do. And if you have some interesting book recommendations, please <a href=\"https://twitter.com/therealboone\">let me know on Twitter</a>, and be sure to check out some <a href=\"https://www.falldowngoboone.com/blog/free-online-web-design-and-dev-books/\">free online books</a> I’ve previously written about.</p>\n<p>Until tomorrow!</p>\n",
      "date_published": "2021-02-15T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/the-details-element/",
      "url": "https://www.falldowngoboone.com/blog/the-details-element/",
      "title": "The details element",
      "content_html": "<p>The <code>details</code> element is one of my favorite HTML elements. Yes, I have favorite HTML elements. Yes, I know that’s weird.</p>\n<h2 id=\"the-disclosure-pattern\" tabindex=\"-1\">The Disclosure pattern<a class=\"c-anchor-link\" href=\"#the-disclosure-pattern\" aria-label=\"permalink\" aria-describedby=\"the-disclosure-pattern\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So, what does this wonderful element do? Out of the box, it’s a way to natively achieve the <a href=\"https://www.w3.org/TR/wai-aria-practices-1.2/#disclosure\">disclosure pattern</a>.</p>\n<p>The disclosure pattern involves some content and a button (the <code>summary</code> element) that controls the visibility of that content. When the content is hidden, the button shows the content. When the content is shown, the button hides the content.</p>\n<p class=\"codepen\" data-height=\"265\" data-theme-id=\"dark\" data-default-tab=\"html,result\" data-user=\"falldowngoboone\" data-slug-hash=\"QWGdaNX\" style=\"height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"Details\">\n  <span>See the Pen <a href=\"https://codepen.io/falldowngoboone/pen/QWGdaNX\">\n  Details</a> by Ryan Boone (<a href=\"https://codepen.io/falldowngoboone\">@falldowngoboone</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>\n<p>Previously this was something that you could only do with JavaScript. And while it wasn’t difficult to do, I love when I can replace JavaScript with a native element that Just Works.™</p>\n<h2 id=\"what%E2%80%99s-it-good-for%3F\" tabindex=\"-1\">What’s it good for?<a class=\"c-anchor-link\" href=\"#what%E2%80%99s-it-good-for%3F\" aria-label=\"permalink\" aria-describedby=\"what%E2%80%99s-it-good-for%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p><code>details</code> is a perfect fit for FAQs. You don’t even have to do that much extra styling.</p>\n<p class=\"codepen\" data-height=\"265\" data-theme-id=\"dark\" data-default-tab=\"html,result\" data-user=\"falldowngoboone\" data-slug-hash=\"PobWvKq\" style=\"height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"Native FAQ\">\n  <span>See the Pen <a href=\"https://codepen.io/falldowngoboone/pen/PobWvKq\">\n  Native FAQ</a> by Ryan Boone (<a href=\"https://codepen.io/falldowngoboone\">@falldowngoboone</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>\n<p>And even though <code>details</code> isn’t a native accordion element (personally, I would rather have a <code>tabs</code> element), it goes a long way toward a nicer progressive enhancement experience:</p>\n<p class=\"codepen\" data-height=\"265\" data-theme-id=\"dark\" data-default-tab=\"html,result\" data-user=\"falldowngoboone\" data-slug-hash=\"xxRgWyV\" style=\"height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"Cheap accordion\">\n  <span>See the Pen <a href=\"https://codepen.io/falldowngoboone/pen/xxRgWyV\">\n  Cheap accordion</a> by Ryan Boone (<a href=\"https://codepen.io/falldowngoboone\">@falldowngoboone</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>\n<p>Just bear in mind that you’ll need to add some extra <a href=\"https://w3c.github.io/aria-practices/examples/accordion/accordion.html\">ARIA roles and keyboard support</a> on top of the default element.</p>\n<h2 id=\"menus\" tabindex=\"-1\">Menus<a class=\"c-anchor-link\" href=\"#menus\" aria-label=\"permalink\" aria-describedby=\"menus\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>One particular type of use for <code>details</code> is really why I’m so fascinated with them. GitHub has implemented a pattern to use the element for their <a href=\"https://docs.google.com/presentation/d/1hvnPpsJo44BTPfJx28CV95vqk_dt6na1awUbk0kmZYM/edit#slide=id.g3e31444916_0_48\">menus</a>. It’s pretty ingenious.</p>\n<p>My favorite part of their implementation is adding a pseudo-element to the <code>summary</code> element that covers the entire screen. This elegantly closes the menu with an outside click:</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token selector\">[open] > summary:before</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token property\">position</span><span class=\"token punctuation\">:</span> fixed<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">top</span><span class=\"token punctuation\">:</span> 0<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">right</span><span class=\"token punctuation\">:</span> 0<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">bottom</span><span class=\"token punctuation\">:</span> 0<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">left</span><span class=\"token punctuation\">:</span> 0<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 80<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">display</span><span class=\"token punctuation\">:</span> block<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">cursor</span><span class=\"token punctuation\">:</span> default<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">content</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\" \"</span><span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">background</span><span class=\"token punctuation\">:</span> transparent<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token selector\">.details-menu</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token property\">position</span><span class=\"token punctuation\">:</span> absolute<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">top</span><span class=\"token punctuation\">:</span> 100%<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">left</span><span class=\"token punctuation\">:</span> 0<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">z-index</span><span class=\"token punctuation\">:</span> 100<span class=\"token punctuation\">;</span><br>\t<span class=\"token comment\">/* more specific styles...*/</span><br><span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"gotchas\" tabindex=\"-1\">Gotchas<a class=\"c-anchor-link\" href=\"#gotchas\" aria-label=\"permalink\" aria-describedby=\"gotchas\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Of course, it wouldn’t be the web if it didn’t have any gotchas. First, <code>[summary</code> styling](<a href=\"https://css-tricks.com/quick-reminder-that-details-summary-is-the-easiest-way-ever-to-make-an-accordion/\">https://css-tricks.com/quick-reminder-that-details-summary-is-the-easiest-way-ever-to-make-an-accordion/</a>) is a bit inconsistent across browsers, but <a href=\"https://www.smashingmagazine.com/2020/11/standardizing-select-native-html-form-controls/\">nowhere near as weird as other elements</a>.</p>\n<p>Second, <code>summary</code>s can include a single heading element (<code>h1–6</code>), but because it natively carries the implicit ARIA role of <code>button</code>, any children, including headings, will be stripped of their semantic role. Depending on what’s used, certain <a href=\"https://www.scottohara.me/blog/2018/09/03/details-and-summary.html#screen-reader-support\">screen reader and browser combinations may not recognize heading children</a> or allow them to be used for navigation.</p>\n<p>Finally, there is no support in Internet Explorer, which is becoming less and less of a problem every day. There is a <a href=\"https://github.com/javan/details-element-polyfill\">polyfill</a>, but I would simply let the content display completely. Unless it’s absolutely necessary, sending more JavaScript to less capable browsers just for consistency’s sake doesn’t make much sense to me.</p>\n<h2 id=\"semantics-for-the-win\" tabindex=\"-1\">Semantics for the win<a class=\"c-anchor-link\" href=\"#semantics-for-the-win\" aria-label=\"permalink\" aria-describedby=\"semantics-for-the-win\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So, <code>details</code> provides a simple, semantic way to implement the common disclosure pattern. Its flexibility and availability make it a powerful addition to any frontend developer’s arsenal.</p>\n<p>Do you have a favorite HTML element? <a href=\"https://twitter.com/therealboone\">I would love to hear about it</a>. And if you’re reading on Dev Community, please consider liking this post and sharing it with others. It makes me feel all warm inside and stuff.</p>\n<p>Till next time!</p>\n",
      "date_published": "2021-02-14T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/the-address-element/",
      "url": "https://www.falldowngoboone.com/blog/the-address-element/",
      "title": "The address element",
      "content_html": "<p>Did you know there’s an <code>address</code> element? Well, brace yourself, because there is! But its use has been a source of confusion until recently.</p>\n<p>In the past, the <code>address</code> element was strictly used for content author info, something it’s still useful for:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>article</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token comment\">&lt;!-- article content --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>footer</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>Like my stuff? As the kids say, drop me a line via electronic mail:<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>address</span><span class=\"token punctuation\">></span></span><br>      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>a</span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>mailto:rick.cooldood78@example.com<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Ricky Cooldood 😎<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>a</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>address</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>footer</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>article</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Note that this example has the <code>address</code> element nested within a sectioning element, in this case, an <code>article</code>. This is what associates the contact information with the content. If you wanted to associate it with the entire site, you would drop it into the site’s main <code>footer</code>.</p>\n<p>Of course, you would think that you could use an <code>address</code> element for addresses as well, but that has not always been the case. Thankfully, a recent <a href=\"https://www.w3.org/TR/html52/grouping-content.html#the-address-element\">change in spec</a> allows for the one thing you would think it could be used for:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>address</span><span class=\"token punctuation\">></span></span><br>  Richard Cooldood<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>br</span><span class=\"token punctuation\">></span></span><br>  1234 No Way Yes Way<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>br</span><span class=\"token punctuation\">></span></span><br>  Awesome, USA 77777<br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>address</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This makes me incredibly happy. Probably too happy.</p>\n<p>Anyway, if you need more granular semantics around an address, you can use a structured data format like <a href=\"https://schema.org/address\">Microdata or RDFa</a>.</p>\n<p>If you’d like to hear more about structured data, <a href=\"https://twitter.com/therealboone\">let me know</a>, and while you’re at it, hit the follow button, because I’m going to keep writing stuff and you might as well read it, right?</p>\n",
      "date_published": "2021-02-13T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/fixing-all-the-things/",
      "url": "https://www.falldowngoboone.com/blog/fixing-all-the-things/",
      "title": "Fixing all the things",
      "content_html": "<p>If you didn’t already know, <a href=\"https://benmyers.dev/blog/css-can-influence-screenreaders/\">your CSS can influence screen readers</a>. One of the most surprising things to me was learning that VoiceOver removes list semantics from <code>ul</code>s and <code>ol</code>s when <code>list-style-type: none</code> is applied to them.</p>\n<p>Turns out, this is actually intended behavior:</p>\n<blockquote>\n<p>This [not announcing a list for a groups of links when list-style is set to none] was a purposeful change due to rampant “list”-itis by web developers…Basically, if you remove all default visible indication of the list, there is no indication to a sighted user or screen reader user that the content is a list…</p>\n<p>—James Craig, <a href=\"https://bugs.webkit.org/show_bug.cgi?id=170179#c1\">Webkit Bugzilla</a></p>\n</blockquote>\n<p>This is one of those interesting things that may seem wrong to developers that apparently was annoying accessible technology users. James goes on to say the easiest way to fix this is to explicitly define a list role on the list:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span> <span class=\"token attr-name\">role</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>list<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>\t<span class=\"token comment\">&lt;!-- list content here --></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Unfortunately, as Scott O’Hara reminds us in his <a href=\"https://www.scottohara.me/blog/2019/01/12/lists-and-safari.html\">fantastic write up on this issue</a>, the <a href=\"https://www.w3.org/TR/using-aria/#rule1\">first rule of ARIA</a> is to not use it when there are existing HTML elements that already have the needed role. Scott mentions a nice <a href=\"https://gerardkcohen.me/writing/2017/voiceover-list-style-type.html\">CSS-only fix</a> put forth by <a href=\"https://gerardkcohen.me/index.html\">Gerard Cohen</a> and retweeted by <a href=\"https://www.sarasoueidan.com\">Sara Soueidan</a>:</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token selector\">.list li</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token property\">list-style-type</span><span class=\"token punctuation\">:</span> none<span class=\"token punctuation\">;</span> <span class=\"token comment\">/* remove bullets */</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token selector\">.list li::before</span> <span class=\"token punctuation\">{</span><br>\t<span class=\"token property\">content</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"\\200B\"</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">/* add zero-width space */</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>I think my biggest takeaway from Scott’s article, though, is that “bugs” like this may be best left alone:</p>\n<blockquote>\n<p>While this behavior can be unwelcome in some situations, let’s also not spend too much effort over correcting an over correction which was in response to an over use of unnecessary semantics.</p>\n</blockquote>\n<p>VoiceOver users are used to the quirks that the technology presents. Forcing a consistent experience may end up making things worse. Just like everything else in web development, you need to test with real people.</p>\n<p>When I began my journey of learning about accessibility, I enthusiastically “fixed” everything I could find in my code, usually over-complicating markup and making things worse for people. More often than not, it pays to keep it simple.</p>\n<p>If you’d like to hear more about how I’ve overcomplicated things in the past, check out this <a href=\"https://www.falldowngoboone.com/blog/notes-to-my-younger-self-regarding-accessibility/\">letter to my younger self</a>, or you can just ask me on <a href=\"https://twitter.com/therealboone\">Twitter</a> about all the hot garbage code I’ve been known to write. Maybe you can learn from my (many) past mistakes.</p>\n",
      "date_published": "2021-02-12T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/how-i-test-for-accessibility/",
      "url": "https://www.falldowngoboone.com/blog/how-i-test-for-accessibility/",
      "title": "How I test for accessibility",
      "content_html": "<p>I wanted to share what my typical accessibility testing sessions look like. This is a quick over, but I hope you find it helpful (and if you haven’t done so yet, check out some <a href=\"https://www.falldowngoboone.com/blog/accessibility-quick-wins/\">accessibility quick wins</a> I wrote about).</p>\n<h2 id=\"what-i-typically-do\" tabindex=\"-1\">What I typically do<a class=\"c-anchor-link\" href=\"#what-i-typically-do\" aria-label=\"permalink\" aria-describedby=\"what-i-typically-do\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>When I’m developing new UI, I inspect with browser dev tools, typically to confirm labels and semantic roles. I test on Chrome, Safari Technology Preview, and Firefox DeveloperEdition, but I probably lean the most on <a href=\"https://developers.google.com/web/tools/chrome-devtools/accessibility/reference\">Chrome DevTools accessibility tools</a>.</li>\n<li>Next, I’ll run <a href=\"https://www.deque.com/axe/\">axe-core</a> and <a href=\"https://wave.webaim.org\">Wave</a> against the page. Automated accessibility tools like these only catch about <a href=\"https://accessibility.blog.gov.uk/2017/02/24/what-we-found-when-we-tested-tools-on-the-worlds-least-accessible-webpage/\">40% of accessibility bugs</a>, but they’re a great way to find any low-hanging fruit before manual testing.</li>\n<li>If the feature I’m building requires user interaction (and it usually does), I will <a href=\"https://webaim.org/techniques/keyboard/\">test with a keyboard</a>. The first thing I check is to see if I can navigate without a mouse. If I can’t see what element has focus on the screen, that’s an immediate fail. I next check if tab order is correct. Finally, I check user interactions (can I open and close widgets with just a keyboard, is there proper focus trapping, etc.).</li>\n</ul>\n<h2 id=\"what-i-should-do\" tabindex=\"-1\">What I should do<a class=\"c-anchor-link\" href=\"#what-i-should-do\" aria-label=\"permalink\" aria-describedby=\"what-i-should-do\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<ul>\n<li>Test with users. We employ a third-party company that audits our code after we launch a new release, but I’d love to have them involved earlier on (preferably during the design iteration phase).</li>\n<li>Test on Windows (at least Chrome + NVDA). I have no excuse. I’m on a Mac, but I’m running Windows via VMWare Fusion, so I need to Just Do It.</li>\n<li>Test consistently on mobile. Chalk this up to convenience. Or inconvenience. It’s next-to-impossible to inspect our developer environment outside of our work computers, so I’m relegated to testing on the Xcode Simulator. I’m hoping we’ll make some changes soon that will open this up more, but for now, I’m stuck with our staging environment and a ridiculously long feedback loop.</li>\n</ul>\n<p>I’m certain this list will continue to grow, but for now I hope it gives you a sense of where to start. If you have any questions or suggestions, I’m always up for a discussion on <a href=\"https://twitter.com/therealboone\">Twitter</a>.</p>\n<p>Until tomorrow!</p>\n",
      "date_published": "2021-02-11T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/notes-to-my-younger-self-regarding-accessibility/",
      "url": "https://www.falldowngoboone.com/blog/notes-to-my-younger-self-regarding-accessibility/",
      "title": "Notes to my younger self: Regarding accessibility",
      "content_html": "<p>Hello, my younger self. How are things? I understand you’re learning about the amazing world of web accessibility, something I wholeheartedly endorse.</p>\n<p>Actually, that’s why I’m writing to you. What I’m about to tell you might hurt, but I think you can handle it. There are some things you’re doing right now, things that you might think are helpful. Well, uh, they really aren’t. In fact, they’re pretty terrible.</p>\n<h2 id=\"you-don%E2%80%99t-need-all-those-nav-elements\" tabindex=\"-1\">You don’t need all those <code>nav</code> elements<a class=\"c-anchor-link\" href=\"#you-don%E2%80%99t-need-all-those-nav-elements\" aria-label=\"permalink\" aria-describedby=\"you-don%E2%80%99t-need-all-those-nav-elements\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>First, why so many <code>nav</code>s on a single page? Multiple <code>nav</code> elements can create a lot of unnecessary noise for screen reader users. Remember what the <code>[nav</code> element spec](<a href=\"https://html.spec.whatwg.org/multipage/sections.html#the-nav-element\">https://html.spec.whatwg.org/multipage/sections.html#the-nav-element</a>) says:</p>\n<blockquote>\n<p>Not all groups of links on a page need to be in a nav element — the element is primarily intended for sections that consist of <strong>major navigation blocks [emphasis mine].</strong></p>\n</blockquote>\n<p><em>Major</em> navigation blocks. Not every single link list in the <code>footer</code>. C’mon, man!</p>\n<p>Oh, and if you must have multiple <code>nav</code>s, make sure you label any that aren’t the primary site navigation:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>nav</span> <span class=\"token attr-name\">aria-labelledby</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>nav-label<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>\t<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h2</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>nav-label<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Secondary<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h2</span><span class=\"token punctuation\">></span></span><br>\t<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token comment\">&lt;!-- links in here --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>nav</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Alternatively, you could use <code>aria-label</code>:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>nav</span> <span class=\"token attr-name\">aria-label</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>secondary<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>\t<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token comment\">&lt;!-- links in here --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>nav</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Just keep in mind that in the far, far distant future of 2021, content in <code>aria-label</code> still isn’t translatable.</p>\n<h2 id=\"navigation-links-aren%E2%80%99t-menu-items\" tabindex=\"-1\">Navigation links aren’t menu items<a class=\"c-anchor-link\" href=\"#navigation-links-aren%E2%80%99t-menu-items\" aria-label=\"permalink\" aria-describedby=\"navigation-links-aren%E2%80%99t-menu-items\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Here’s a snippet of actual code you wrote with your actual hands:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>nav</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>...<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>...<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>...<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>a</span> <span class=\"token attr-name\">role</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>menuitem<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>...<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>...<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">aria-expanded</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>false<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">aria-controls</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>...<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">aria-haspopup</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>true<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>\t\t\t\t...<br>\t\t\t<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>a</span><span class=\"token punctuation\">></span></span><br>\t\t\t<span class=\"token comment\">&lt;!-- more insanity omitted --></span></code></pre>\n<p>I see you’ve learned about <code>aria</code> attributes. That’s…nice.</p>\n<p>There’s just so much wrong here, but what I want to focus on is the <code>role=&quot;menuitem&quot;</code>. All <a href=\"https://www.w3.org/TR/wai-aria-1.1/#menu\">menu roles</a> are meant for application menus, not navigation links. Unless you’re building the browser equivalent of Photoshop, <a href=\"https://adrianroselli.com/2017/10/dont-use-aria-menu-roles-for-site-nav.html\">stay away from them</a>.</p>\n<p>Also, I don’t know what you’re up to with all those <code>aria</code> attributes, but I know it can’t be good.</p>\n<h2 id=\"hide-invisible-content-from-screen-readers\" tabindex=\"-1\">Hide invisible content from screen readers<a class=\"c-anchor-link\" href=\"#hide-invisible-content-from-screen-readers\" aria-label=\"permalink\" aria-describedby=\"hide-invisible-content-from-screen-readers\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Remember when you coded up that swanky dropdown menu that faded in and out? Yeah, that was slick! Remember the CSS you used?</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">.dropdown-panel </span><span class=\"token punctuation\">{</span><br>\t<span class=\"token property\">opacity</span><span class=\"token punctuation\">:</span> 0<span class=\"token punctuation\">;</span><br>\t<span class=\"token property\">transition</span><span class=\"token punctuation\">:</span> opacity 200ms<span class=\"token punctuation\">;</span><br>\t<span class=\"token comment\">// other stuff</span><br><br>\t<span class=\"token selector\"><span class=\"token parent important\">&amp;</span>.is-open </span><span class=\"token punctuation\">{</span><br>\t\t<span class=\"token property\">opacity</span><span class=\"token punctuation\">:</span> 1<span class=\"token punctuation\">;</span><br>\t<span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>First of all, kudos on animating <code>opacity</code>. You’re thinking about performance, and that’s a Good Thing.™ But I think you’re missing something.</p>\n<p>Did you know that elements set to <code>opacity: 0</code> can still be read by screen readers? By the look on your face, I can see you didn’t know that. Something else you probably didn’t realize is since <code>opacity: 0</code> doesn’t remove elements from the focus order, keyboard users get to tab through all 500 invisible links in your mega site nav.</p>\n<p>If you are hiding elements for sighted users to reduce cognitive noise, you should do the same for screen readers. Remember that accessibility is about creating equivalent experiences. <code>display: none</code> is a much better choice here to completely hide the panel from everyone.</p>\n<p>What’s that? You can’t animate <code>opacity</code> when you’re using <code>display: none</code>? Well, use JavaScript here, ya silly. It’s already a requirement for your dropdown menu to work. Here’s an <a href=\"https://codepen.io/falldowngoboone/pen/qBqaRvx?editors=0010\">example Codepen</a>.</p>\n<h2 id=\"that%E2%80%99s-it-for-now\" tabindex=\"-1\">That’s it for now<a class=\"c-anchor-link\" href=\"#that%E2%80%99s-it-for-now\" aria-label=\"permalink\" aria-describedby=\"that%E2%80%99s-it-for-now\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>There’s more to discuss, for sure, but frankly, I don’t have the strength to go on. Perhaps some other time. I want to leave you with some advice.</p>\n<p>First, one day you’ll want to write a <a href=\"https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/\">daily blog post for an entire month</a>. Make sure you do more planning so you don’t end up writing weird stuff like this at the last minute. Second, reach out to me through this magical time machine internet connection and <a href=\"https://twitter.com/therealboone\">say hi to me on Twitter</a>. I get lonely sometimes.</p>\n<p>See you in the future!</p>\n",
      "date_published": "2021-02-10T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/accessibility-quick-wins/",
      "url": "https://www.falldowngoboone.com/blog/accessibility-quick-wins/",
      "title": "Accessibility quick wins",
      "content_html": "<p>I sometimes give talks on Web accessibility, and one of the top questions I get is: <em>What can I do right now to make my website more accessible?</em> When I began <em>practicing</em> accessibility, I would’ve probably talked about WAI-ARIA authoring practices, and adding <code>aria</code> roles, and managing focus with JavaScript. That’s certainly true for more complex UI, but most of us aren’t building Twitter.</p>\n<p>In reality, the most common accessibility problems can be fixed with simple solutions. What follows is a list of some of the quick wins I’ve compiled from online survey results, third-party auditors, and the A11y Slack group.</p>\n<h2 id=\"use-colors-with-the-proper-contrast\" tabindex=\"-1\">Use colors with the proper contrast<a class=\"c-anchor-link\" href=\"#use-colors-with-the-proper-contrast\" aria-label=\"permalink\" aria-describedby=\"use-colors-with-the-proper-contrast\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>This one’s truly easy. <a href=\"https://developers.google.com/web/tools/chrome-devtools/accessibility/reference#contrast\">Check the color contrast</a> on your page. This should be the designer’s job, but frontend developers should be diligent to double-check and make suggestions as necessary. Usually, it doesn’t take many tweaks to ensure the correct contrast ratio.</p>\n<h2 id=\"add-an-alt-attribute-to-all-your-images\" tabindex=\"-1\">Add an <code>alt</code> attribute to all your images<a class=\"c-anchor-link\" href=\"#add-an-alt-attribute-to-all-your-images\" aria-label=\"permalink\" aria-describedby=\"add-an-alt-attribute-to-all-your-images\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>This is a super-quick win. According to the <a href=\"https://webaim.org/projects/million/\">2020 WebAIM Million</a> survey, one of the top accessibility errors online was missing <code>alt</code> attributes on images. It’s always a good idea to include <a href=\"https://moz.com/learn/seo/alt-text\">effective alt text</a> on images that are not purely decorative.</p>\n<p>It’s important to note that <strong>if you don’t add an alt attribute, the default behavior of screen readers is to announce the source link of the image,</strong> which can be annoying, especially if you’re including hashes in the filename for cache-busting. So what about images that <em>are</em> decorative? Use a null value (<code>alt=&quot;&quot;</code>). Better yet, add decorative images as background images via CSS (<code>background-image: url('link/to/image');</code>).</p>\n<h2 id=\"ensure-all-links-have-meaningful-labels\" tabindex=\"-1\">Ensure all links have meaningful labels<a class=\"c-anchor-link\" href=\"#ensure-all-links-have-meaningful-labels\" aria-label=\"permalink\" aria-describedby=\"ensure-all-links-have-meaningful-labels\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>One way screen reader users can quickly navigate content is by jumping through all the available page links. When all the links on the page are either “Click here”, nonsense (e.g. icon fonts), or empty (e.g. an SVG icon without a label), navigating by page links becomes impossible.</p>\n<p>If you’re being asked to create “Click here” links, talk to the content authors about the difficulties of that type of phrasing. As a bonus, using <a href=\"https://moz.com/learn/seo/anchor-text\">descriptive link text is better for your SEO</a>. You can learn more about link text in WebAIM’s article about <a href=\"https://webaim.org/techniques/hypertext/link_text\">links and hypertext</a>, and Scott O’Hara has a great article I continually reference for <a href=\"https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html\">accessible SVGs</a>.</p>\n<h2 id=\"label-all-form-elements\" tabindex=\"-1\">Label all form elements<a class=\"c-anchor-link\" href=\"#label-all-form-elements\" aria-label=\"permalink\" aria-describedby=\"label-all-form-elements\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>This goes along with the last tip. Form elements (<code>input</code>, <code>textarea</code>, <code>select</code>, <code>button</code>, etc,) must have properly associated labels.</p>\n<p><code>button</code> elements are easy to label:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span><span class=\"token punctuation\">></span></span>I'm a label<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>For the rest, you need to associate a <code>label</code> element with the form element in question:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>label</span> <span class=\"token attr-name\">for</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>element-id<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>Username<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>label</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>element-id<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>username<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span></code></pre>\n<p>Notice the <code>label</code> has a <code>for</code> attribute that’s the same as its sibling <code>input</code>’s <code>id</code>. That’s how accessible technology knows what label is associated with what input. <strong>Avoid using <code>placeholder</code> as a label.</strong> In fact, you probably should <a href=\"https://www.smashingmagazine.com/2018/06/placeholder-attribute/\">avoid using the placeholder attribute altogether</a>.</p>\n<h2 id=\"don%E2%80%99t-use-aria-unless-you%E2%80%99ve-exhausted-all-other-options\" tabindex=\"-1\">Don’t use ARIA unless you’ve exhausted all other options<a class=\"c-anchor-link\" href=\"#don%E2%80%99t-use-aria-unless-you%E2%80%99ve-exhausted-all-other-options\" aria-label=\"permalink\" aria-describedby=\"don%E2%80%99t-use-aria-unless-you%E2%80%99ve-exhausted-all-other-options\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>ARIA (Accessible Rich Internet Applications) is a collection of roles and attributes that enrich plain old HTML to support interactions that are currently not possible with HTML. The first rule of ARIA is <em><a href=\"https://www.w3.org/TR/using-aria/#firstrule\">Don’t use ARIA</a>.</em> Great marketing, right?</p>\n<p>The truth is, modern HTML can cover most UI needs. Don’t believe me? <strong>There are over 100 <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element\">current HTML elements</a>,</strong> and many of them have ARIA roles already baked into them. This brings me to my next tip.</p>\n<h2 id=\"use-semantic-html-when-possible\" tabindex=\"-1\">Use semantic HTML when possible<a class=\"c-anchor-link\" href=\"#use-semantic-html-when-possible\" aria-label=\"permalink\" aria-describedby=\"use-semantic-html-when-possible\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p><code>div</code>s and <code>span</code>s are great to style with, but they have no meaning whatsoever to accessible technology. <strong>Wrapping large blocks of text directly in a <code>div</code> should be avoided with few exceptions,</strong> and those exceptions involve manually adding semantic meaning via <code>aria</code> roles.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span><span class=\"token punctuation\">></span></span>This text has no meaning whatsoever because divs are a <br>generic container.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>This is a paragraph of content.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Wrapping text in a <code>span</code> is a great way to style a select group of text, just make sure it’s inside another element that has semantic meaning:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>This is a paragraph. <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>red<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>This span has no semantic meaning, <br>but we're still inside a paragraph, so it's fine.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span><span class=\"token punctuation\">></span></span>Without a semantic parent, this text has no meaning.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span></code></pre>\n<h2 id=\"don%E2%80%99t-hide-the-focus-ring\" tabindex=\"-1\">Don’t hide the focus ring<a class=\"c-anchor-link\" href=\"#don%E2%80%99t-hide-the-focus-ring\" aria-label=\"permalink\" aria-describedby=\"don%E2%80%99t-hide-the-focus-ring\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>You can restyle the focus ring, but make sure it meets <a href=\"https://www.w3.org/TR/WCAG21/#contrast-enhanced\">contrast guidelines</a>. The reason is keyboard users need to be able to see where they are while tabbing through interactive elements.</p>\n<p>One reason why the focus ring gets hidden is that clicking on interactive elements in certain browsers focuses them, activating the focus styling. If you only want to show the focus indicator for keyboard users, try <code>[focus-visible](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible#selectively_showing_the_focus_indicator)</code>.</p>\n<h2 id=\"don%E2%80%99t-wrap-large-blocks-of-markup-in-links\" tabindex=\"-1\">Don’t wrap large blocks of markup in links<a class=\"c-anchor-link\" href=\"#don%E2%80%99t-wrap-large-blocks-of-markup-in-links\" aria-label=\"permalink\" aria-describedby=\"don%E2%80%99t-wrap-large-blocks-of-markup-in-links\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So when would you want to do this? How about a cards that link to other pages:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>a</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>card<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/page<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h2</span><span class=\"token punctuation\">></span></span>Title of Article<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h2</span><span class=\"token punctuation\">></span></span><br> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>Small blurb here.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>a</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Why avoid this? For starters, you can’t easily select text inside of links. Second of all, links are announced in screen readers by reading off the contained text content. <strong>The more <a href=\"https://webaim.org/techniques/hypertext/link_text#link_length\">content inside the link</a>, the more inconvenient the link text becomes.</strong> I’ve made <a href=\"https://codepen.io/falldowngoboone/pen/LYVdvQx\">a Codepen</a> showing a couple of approaches to get around this.</p>\n<h2 id=\"validate-your-html\" tabindex=\"-1\">Validate your HTML<a class=\"c-anchor-link\" href=\"#validate-your-html\" aria-label=\"permalink\" aria-describedby=\"validate-your-html\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Valid HTML is important to ensure that your content renders correctly for years to come and that it works well with accessible technology. Little things like adding closing tags, properly nesting elements, and following the HTML spec can make a huge difference for your SEO as well. The W3C has a solid <a href=\"https://validator.w3.org\">HTML validator</a> that works well.</p>\n<h2 id=\"specify-the-document-language\" tabindex=\"-1\">Specify the document language<a class=\"c-anchor-link\" href=\"#specify-the-document-language\" aria-label=\"permalink\" aria-describedby=\"specify-the-document-language\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>This one’s something you should probably put into a snippet. Specifying the document’s language helps translation apps, improves the SEO of the page, and improves a screen reader’s ability to pronounce certain words. Here’s how that looks:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>html</span> <span class=\"token attr-name\">lang</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>en<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>...<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>html</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Of course, use the <a href=\"https://www.sitepoint.com/web-foundations/iso-2-letter-language-codes/\">ISO language code</a> that pertains to your chosen document language. This attribute is inherited by all children, so placing it on the document element (<code>html</code>)</p>\n<h2 id=\"in-closing\" tabindex=\"-1\">In closing<a class=\"c-anchor-link\" href=\"#in-closing\" aria-label=\"permalink\" aria-describedby=\"in-closing\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you keep this list in mind, you will be well on your way to ensuring your website is accessible to the widest audience possible. Not only will it improve performance, SEO, and readability for <em>all</em> of your users, it’s the right thing to do.</p>\n<p>If you enjoyed this article, please consider sharing this article with others. And if you have any questions about any of the points above, feel free to <a href=\"https://twitter.com/therealboone\">ask me on Twitter</a>.</p>\n<p>Until tomorrow!</p>\n",
      "date_published": "2021-02-09T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/accessible-content/",
      "url": "https://www.falldowngoboone.com/blog/accessible-content/",
      "title": "Accessible Content",
      "content_html": "<p>When I was first learning about accessibility on the Web, I stumbled across <a href=\"https://webaim.org\">WebAIM</a> (Web Accessibility In Mind), a fantastic resource for all things accessibility.</p>\n<p>They have a ton of great articles focusing on different aspects of web accessibility, but one of my favorites I keep going back to is <a href=\"https://webaim.org/articles/pour/\">Constructing a POUR Website</a>. It helps unravel the <a href=\"https://www.w3.org/WAI/WCAG21/Understanding/intro#understanding-the-four-principles-of-accessibility\">Web Accessibility Guidelines principles of accessibility</a> and helps shift the focus away from <em>how</em> to make content accessible to <em>why</em>.</p>\n<p>In summary, the WCAG guiding principles state that <strong>accessible content is perceivable</strong> (people can perceive the content with any of their available senses), <strong>operable</strong> (people can interact with the content as needed), <strong>understandable</strong> (people can understand the content and how to navigate it), <strong>and robust</strong> (the content can be interpreted by an array of technologies). These principles form the acronym POUR, which is an easy way to remember them.</p>\n<p>To explore these principles in more depth, check out the article. And if you have any questions or would like to discuss it, feel free to <a href=\"https://twitter.com/therealboone\">reach out to me on Twitter</a>.</p>\n",
      "date_published": "2021-02-08T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/lean-into-the-fear/",
      "url": "https://www.falldowngoboone.com/blog/lean-into-the-fear/",
      "title": "Lean into the fear",
      "content_html": "<p><a href=\"https://twitter.com/chantastic?lang=en\">Chantastic</a> recently spoke at <a href=\"https://www.meetup.com/ReactJSDallas/\">ReactJS Dallas</a> about dealing with Imposter Syndrome. One of my favorite moments was when he talked about being asked to take over <a href=\"https://reactpodcast.com\">React Podcast</a> hosting duties. He said he was afraid he was going to say the wrong thing to the amazing developers he would be interviewing.</p>\n<p>Eventually he realized that fear was the only reason not to take the offer. So instead of passing up a fantastic opportunity, he decided to lean into the fear.</p>\n<p>Listening to someone I’ve heard interview JavaScript heavyweights on my iPhone for the past few years talk about facing his own fears renewed my long-held belief that I need to lean into the things that make me afraid.</p>\n<p>The first time I was asked to give a software talk, I had been a professional developer for less than a year. I was terrified, but I did it. Was it good? Meh. But the important part was I stepped out of my comfort zone. I still experience a fear of public speaking, but the more I push through that fear, the quieter its gets.</p>\n<p>If fear is the only thing keeping you from doing something that could otherwise enrich your life, lean into it. Intentionally do something <em>because</em> it scares you. Start a YouTube channel. Give a talk at a Meetup. Try <a href=\"https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/\">blogging for 28 days straight</a>.</p>\n<p>Push past the fear, get comfortable with being uncomfortable. You never know what it might lead to.</p>\n<p>Have you ever let fear hold you back from doing something? Make an action plan today to lean into that fear, and let others know so they can encourage you. Don’t know where to start? <a href=\"https://twitter.com/therealboone\">I’m glad to answer any questions</a>.</p>\n",
      "date_published": "2021-02-07T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/your-experience-counts/",
      "url": "https://www.falldowngoboone.com/blog/your-experience-counts/",
      "title": "Your experience counts",
      "content_html": "<p>On my journey from designer to <a href=\"https://www.falldowngoboone.com/blog/on-changing-careers/\">becoming a developer</a>, I often wondered if I needed a Computer Science degree. This is also one of the most common questions I get from others looking to jump into development from another career.</p>\n<p>I began college as a Drama major and eventually switched to a Communications degree with an emphasis in Film and Broadcast. Then I went into graphic design. Not exactly the straightest path to software engineering.</p>\n<p>For a long time, I allowed my lack of formal development education to be a source of insecurity. No matter what I accomplished or what I learned, I always felt like I was missing something. It fueled my appetite for growth, but it robbed me of my confidence.</p>\n<p>Something that I realized as a designer, though, was even though I didn’t have a formal education in a particular field of study, the education and experience I had acquired up to that point was more relevant than I initially thought. I began reframing the idea that I had no applicable experience into the idea that all experience counts.</p>\n<p>In acting, I learned to put myself in the shoes of another person, useful for testing interfaces and writing readable code. In film school, I learned how to tell a story, something that’s useful in crafting version control commit history and interpersonal communication. Finally, in design, I learned how to build systems that scale, which is invaluable to creating software architecture.</p>\n<p>There are many different paths to becoming a software developer. Whether or not you should get a Computer Science degree is really something only you can answer. I didn’t need one to become a developer, but the process of getting one can help you choose what field of development you want to pursue.</p>\n<p>I think the important takeaway from this is, if you’re struggling with insecurities about a lack of education, look at what you do have. Start to bridge what you know and what you’ve done to what you want to do. Chances are your experiences and interests already have a common theme and share a common skillset.</p>\n<p>Your experience counts more than you think.</p>\n<p>What has your journey looked like? Has it been as roundabout as mine? Or maybe even more…unconventional? <a href=\"https://twitter.com/therealboone\">I would love to hear all about it</a>.</p>\n<p>Thanks for reading. Until tomorrow!</p>\n",
      "date_published": "2021-02-06T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/debugging-javascript-with-binary-search/",
      "url": "https://www.falldowngoboone.com/blog/debugging-javascript-with-binary-search/",
      "title": "Debugging JavaScript with binary search",
      "content_html": "<p>I recently had to debug a problem that existed somewhere in the middle of around 460 lines of JavaScript spaghetti. Debugging was useless because the bug was taking down dev tools! The approach I took was something that I often employ when facing a seemingly impossible task like this.</p>\n<p>First, let me pull up a chair, sit down in it backwards and type out some words about <a href=\"https://www.khanacademy.org/computing/computer-science/algorithms/binary-search/a/binary-search\">binary search</a>. It’s a search pattern that utilizes a divide and conquer algorithm to locate data.</p>\n<p>Let’s say you need to look up something located in a huge heap of sorted data. Oh, maybe you’re looking up a friend’s phone number in a phone book (I mean, not like I ever had to do that in my lifetime…).</p>\n<p>Anyway, you need to find a friend’s number, so the first thing you do is open the phone book to the very middle. Is your friend’s last name on the page? Chances are it’s not. Since you know the alphabet, you know whether your friend’s last name comes before or after the page you’re on.</p>\n<p>Now this is an important point. Let’s say your friend’s last name comes before the page you’re on. In binary search, <strong>you throw away the data you know doesn’t contain what you’re looking for.</strong> This leaves you with half the data to search through.</p>\n<p>Now you do the same steps over and over, dividing the data, checking where you are, and throwing away the half that doesn’t contain what you’re looking for. This algorithm is simple and elegantly fast (a worst-case <a href=\"https://www.geeksforgeeks.org/understanding-time-complexity-simple-examples/\">time complexity</a> of O(log n), which in plain speak means it remains fast the bigger the dataset you have to search).</p>\n<p>So why did I just blow through five paragraphs on binary search? What was I talking about? Oh, right, debugging.</p>\n<p>To debug this particular problem, I first commented out the entire block of code as a sanity check, then checked to make sure the bug was no longer occurring (setting up a quick <a href=\"https://www.falldowngoboone.com/blog/the-feedback-loop/\">feedback loop</a> is crucial to debugging).</p>\n<p>After confirming I had indeed isolated the bug, I commented out the bottom half of the 460 line code block (I always skip commenting out top level function declarations to avoid runtime exceptions that could give me a false positive). A save and refresh showed the bug was still alive and well. I continued to do this until the bug no longer triggered.</p>\n<p>After I isolated the bug to a range of lines, I uncommented everything else, saved, and double-checked my work. After confirming the cause was definitely in the last chunk of code I commented out, it was a matter of doing the binary comment-out-and-save on those remaining lines.</p>\n<p>I found the source of the bug in about an hour, which is pretty good considering it takes about 30 minutes to deploy the code to our testing environment. Yeah, that’s a topic for another post.</p>\n<p>I have been told that repetition helps learning, so let’s do that now. To review:</p>\n<ol>\n<li>Set up a feedback loop</li>\n<li>Confirm the code you are editing is indeed the problem</li>\n<li>Starting from the bottom, comment out half the code, save and refresh</li>\n<li>If the bug remains, repeat Step 3 until the bug is squished; now you know where the bug exists (make sure you double check your work by uncommenting everything but the isolated block of code)</li>\n</ol>\n<p>I’ve used this for layout overflow issues as well (<a href=\"https://css-tricks.com/css-is-awesome/\">CSS is awesome</a>), by deleting huge chunks of a web page in dev tools. It’s an effective, if dirty, solution.</p>\n<p>Sometimes I like using the debugger. Sometimes it’s the good ol’ <code>console.log</code>. But when all else fails, I get out the knife and start carving up code.</p>\n<p>How do you debug your code? <a href=\"https://twitter.com/therealboone\">Let me know</a> and I’ll be your best friend. And I am a very good friend.</p>\n<p>Till tomorrow…</p>\n",
      "date_published": "2021-02-05T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/building-habits-through-relationships/",
      "url": "https://www.falldowngoboone.com/blog/building-habits-through-relationships/",
      "title": "Building habits through relationships",
      "content_html": "<p><em><a href=\"https://jamesclear.com/atomic-habits\">Atomic Habits</a></em> by James Clear is a fantastic read. At its heart, the message of the book is that setting goals is ineffective in the long run. Real, lasting change only comes through building systems—creating the right conditions for doing the right habits.</p>\n<p>One insight Clear offers is we often mirror the habits of those around us, for better or worse. Understanding that, one of the easiest ways to develop desirable life habits is to join a group that shares your interests and is doing what you want to do.</p>\n<p>I intentionally look for groups of people that are learners. I hang out with other developers, attend Meetups (shout out to the <a href=\"https://www.meetup.com/ReactJSDallas/\">ReactJS Dallas</a>!) and conferences, belong to various Slack and Discord groups, and listen to several programming podcasts. This has helped me develop healthy learning habits and provides an outlet to share what I’ve learned.</p>\n<p>Connecting with other people is critical for personal growth, not only because it helps you develop healthy habits and skills, but, more importantly, because it creates connections and friendships that will enrich your life and expand your world view. I want to encourage you to seek out groups of people that are doing what you want to do. You’ll be surprised at what you learn.</p>\n<p>One way to discover groups of people with shared interests is by listening to podcasts. Do you have a favorite podcast? Join their community, and let me know over on the wide wide world of <a href=\"https://twitter.com/therealboone\">Twitter</a>. I’m always looking to expand my listening library (and if you’d like some suggestions, I have a whole list of favorites).</p>\n<p>Until tomorrow!</p>\n",
      "date_published": "2021-02-04T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/web-development-resources/",
      "url": "https://www.falldowngoboone.com/blog/web-development-resources/",
      "title": "Web development resources",
      "content_html": "<p>As a follow up to <a href=\"https://www.falldowngoboone.com/blog/on-changing-careers/\">yesterday’s post</a>, I wanted to share a quick list of online resources that I used to get started in my development career.</p>\n<ul>\n<li><a href=\"https://www.codecademy.com\">Codecademy</a></li>\n<li><a href=\"https://teamtreehouse.com\">Treehouse</a></li>\n<li><a href=\"https://www.edx.org\">EdX</a>, especially anything having to do with Harvard’s <a href=\"https://www.edx.org/course/cs50s-introduction-to-computer-science\">CS50 Introduction to Computer Science</a></li>\n<li><a href=\"https://www.coursera.org\">Coursera</a></li>\n<li><a href=\"https://www.codewars.com\">Codewars</a></li>\n<li><a href=\"https://frontendmasters.com\">Frontend Masters</a>, my absolute favorite resource for deep dive classes</li>\n<li><a href=\"https://egghead.io\">Egghead</a></li>\n<li><a href=\"https://developer.mozilla.org/en-US/\">MDN web docs</a>, the definitive resource for all things web development</li>\n<li><a href=\"https://www.freecodecamp.org\">freeCodeCamp</a>, the ultimate FREE boot camp</li>\n<li><a href=\"https://codepen.io\">Codepen</a>, a great place to experiment with ideas or even build a one-off web page</li>\n</ul>\n<p>I’m always looking to expand my resource list, so if you have a favorite you don’t see here, please let me know on <a href=\"https://twitter.com/therealboone\">Twitter</a>.</p>\n",
      "date_published": "2021-02-03T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/on-changing-careers/",
      "url": "https://www.falldowngoboone.com/blog/on-changing-careers/",
      "title": "On changing careers",
      "content_html": "<p>I had just made the decision to leave my 15-year career as a designer to become a developer, and I had no idea where to start. The only programming I had ever done was building websites for friends and family. I was completely green.</p>\n<p>That was six years ago. Now I’m enjoying my fourth year as an Applications Engineer at The Container Store doing fullstack development.</p>\n<p>I tell you this because maybe you are thinking about jumping careers and you feel stuck, frustrated, and lost. Maybe you feel like it’s never going to happen. Believe me, that’s normal.</p>\n<p>What follows is a short list of things that helped me get through the tough times by keeping my focus on the end goal. It starts with a simple question.</p>\n<h2 id=\"what-motivates-you%3F\" tabindex=\"-1\">What motivates you?<a class=\"c-anchor-link\" href=\"#what-motivates-you%3F\" aria-label=\"permalink\" aria-describedby=\"what-motivates-you%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I have always loved doing creative things, so when I got a job as a designer at a marketing firm in the Dallas/Fort Worth area, I was excited. I thought I would be doing the thing I loved doing more than anything else. A few years in I realized I wasn’t happy, and I didn’t know why.</p>\n<p>A coworker suggested I take the StrengthsFinder test (now <a href=\"https://store.gallup.com/p/en-us/10385/strengthsfinder-2.0-(hardcover)\">CliftonStrengths</a>). Now I am not normally someone that takes personality assessment tests, but I liked StrengthsFinder. It’s actually less about discovering your strengths and more about discovering what motivates you.</p>\n<p>If you don’t want to take an assessment test, try talking to your friends and family. Ask them what they think you’re good at. Pay attention to what you do that makes time fly. Look for commonalities between these things, and write what you learn down.</p>\n<p>Knowing what motivates you gives you an anchor you can always come back to in times of doubt or indecision. And it gives you a point of reference for the next step.</p>\n<h2 id=\"try-your-new-job-on\" tabindex=\"-1\">Try your new job on<a class=\"c-anchor-link\" href=\"#try-your-new-job-on\" aria-label=\"permalink\" aria-describedby=\"try-your-new-job-on\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Knowing my motivation was great, but knowledge without application is useless. At that point, I was leaning in the direction of Web development, but I needed a way to try the role on before making a huge life decision.</p>\n<p>I bought a subscription to <a href=\"https://teamtreehouse.com\">Treehouse</a> and used my lunch hour to watch web development videos and do exercises. I began volunteering at work to design and build marketing emails (coding like it’s 1999). I worked my way up to building brochure sites for clients.</p>\n<p>Finally, I took a big, scary leap. My company announced they were rebranding, and I volunteered to redo their website. It took some convincing, but eventually I had my first official Web project under my belt.</p>\n<p>You may not have an hour for lunch, or you may have limited personal time. Be open to finding anything either at work or at home that you can do to try your new job on right now. Create a plan and stick to it.</p>\n<h2 id=\"focus-on-moving-forward\" tabindex=\"-1\">Focus on moving forward<a class=\"c-anchor-link\" href=\"#focus-on-moving-forward\" aria-label=\"permalink\" aria-describedby=\"focus-on-moving-forward\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Completely changing careers didn’t happen for me overnight. Big changes like that rarely do. You have to be patient and stay consistent.</p>\n<p>I compare this experience to being on a boat in the middle of the ocean. You can’t see your destination, but you know the general direction. Yes, there will occasionally be the need for course correction, but as long as you’re moving forward, you will get there eventually.</p>\n<p>Don’t underestimate the power of tiny, consistent actions. A lot can happen over the span of one year. Don’t lose hope. Chances are you’re closer to land than you think.</p>\n<h2 id=\"now-what%3F\" tabindex=\"-1\">Now what?<a class=\"c-anchor-link\" href=\"#now-what%3F\" aria-label=\"permalink\" aria-describedby=\"now-what%3F\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>As I said, this is a (very) small list of things that helped me make the jump from design to development. If you’re on a similar journey, <a href=\"https://twitter.com/therealboone\">let me know</a>. Oh, and if you’re an aspiring developer, checkout my post on how to <a href=\"https://www.falldowngoboone.com/blog/get-started-with-coding/\">get started with coding</a>.</p>\n<p>Until next time!</p>\n",
      "date_published": "2021-02-02T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/",
      "url": "https://www.falldowngoboone.com/blog/blogruary-28-days-of-posting/",
      "title": "Blogruary: 28 days of posting",
      "content_html": "<p>I suck at blogging. Presently. I <em>presently</em> suck at blogging. I read somewhere that you should qualify negative statements with “presently.” So, yeah, I presently suck at blogging, but I would love to get better at it.</p>\n<p>I’ve tried three or four times to start blogging, and I always fizzle out after a handful of posts. Why? I <em>presently</em> (ah, see what I did there?) struggle with finding value in what I have to say. Of course, that’s a pretty poor excuse to not write.</p>\n<p>The thing is, I love the feeling I get when I help other people learn something. I get to do that every day at my job as a developer at The Container Store (it’s where space comes from; look it up). I’ve also heard <a href=\"https://fs.blog/2012/04/feynman-technique/\">teaching others</a> is a great way to learn, and learning is like one of my top favorite seven things.</p>\n<p>With that in mind, this month I have resolved to write 28 blog posts, including this one. I’m calling it Blogruary because I’m a stickler for naming things. The first ‘r’ is silent, in case you’re wondering.</p>\n<p>You may ask, <em>Ryan, why February?</em> Well, it’s the shortest month of the year and I feel more comfortable doing 28 posts versus 30 or 31 and mind your own business, okay? Geez!</p>\n<p>I’m not going to lie. Going from three blog posts a year to 28 in a month is going to be tough. I’m setting some ground rules to make sure I accomplish my goal. First drafts should take no longer than fifteen minutes to write. Editing should not exceed one hour. And to keep me honest, I will share these blog posts with all my followers on Twitter (hi mom!) as well as on my <a href=\"http://dev.to\">dev.to</a> account.</p>\n<p>The subject matter may be a bit random at times. I’m still trying to figure out what my <em>thing</em> is. But the end goal is to become a better communicator and help others in the process. I hope you come along for the ride.</p>\n",
      "date_published": "2021-02-01T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/year-end-review-2020/",
      "url": "https://www.falldowngoboone.com/blog/year-end-review-2020/",
      "title": "Year-end review 2020",
      "content_html": "<p>2020 is out and I wanted to do a short review of what I did this year, as well as look forward to 2021. This year was difficult to be sure, but in spite of the craziness, or maybe because of it, I was surprisingly able to meet some goals I had previously set.</p>\n<h2 id=\"2020-accomplishments\" tabindex=\"-1\">2020 Accomplishments<a class=\"c-anchor-link\" href=\"#2020-accomplishments\" aria-label=\"permalink\" aria-describedby=\"2020-accomplishments\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In 2020…</p>\n<ul>\n<li><a href=\"https://www.falldowngoboone.com/blog/how-im-redesigning-my-blog/\">I began the complete redesign of my site</a>. I’m super excited about this. It took way too long and involved way too many different frameworks and false starts, but I’m happy with the end result.</li>\n<li>After a year-long drought, I’m writing again. I’m still trying to get into the groove of writing, trying to find my voice, but I think if I can put the time in and stay consistent, I’ll get there. Or at least I’ll get <em>better</em>.</li>\n<li>I delivered two talks this year, both on accessibility on the Web.</li>\n<li>I nabbed a spot at RailsConf2020. Unfortunately I was unable to present due to its cancellation as a live event, but I still see that as an accomplishment.</li>\n<li>At work, I led the effort to completely overhaul our front end tooling, opening the door for more modern CSS and JavaScript, as well as speeding up overall Sass compilation time 25x (honestly, that part was easy since we were still using Compass to compile everything).</li>\n<li>Also at work, we’re wrapping up a year-long project that took about eight months more than it should have. But with shifting priorities due to temporary store closings as well as a focus on uptime to keep up with the increased web traffic, the extended timeline is no surprise.</li>\n</ul>\n<p>I’ve started to see a pattern of excitement when working on developer tools. I really enjoyed putting the front end tool chain together, and I’ve gotten to really take charge over a couple internal tools used department-wide.</p>\n<h2 id=\"2021-opportunities\" tabindex=\"-1\">2021 Opportunities<a class=\"c-anchor-link\" href=\"#2021-opportunities\" aria-label=\"permalink\" aria-describedby=\"2021-opportunities\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In 2021…</p>\n<ul>\n<li>At work, the first thing on my priority list is creating a service that glues all project-dependent services together. Anything that crawls our repositories or consumes our Pivotal data will use this service and it will become the source of truth for all things projects-related. This could possibly be a good excuse to dig into AWS.</li>\n<li>I want to continue working on improving our internal tools as well. It’s an opportunity to grow in building maintainable systems as well as a place to use my design experience. It also gives me something to write about.</li>\n<li>Speaking about writing, my intent is to write more regularly. I think I’m going to start focusing on some of the experiments I do and some of the internal tools work I’m doing at The Container Store. And I’ll definitely try to highlight some of the customer-facing work I do on the website. Communication is a critical skill for developers (code <em>is</em> communication), and writing helps me hone that skill.</li>\n<li>Finally, I would love to do more speaking engagements in 2021. I enjoy talking about React, accessibility, and pretty much anything front end related. I’ve talked about publishing videos as well, so 2021 may be the year that happens.</li>\n</ul>\n<h2 id=\"looking-ahead\" tabindex=\"-1\">Looking ahead<a class=\"c-anchor-link\" href=\"#looking-ahead\" aria-label=\"permalink\" aria-describedby=\"looking-ahead\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>To be honest, it feels weird to be writing about my accomplishments in a year filled with chaos, but I wanted to at least have a written record for future reference. I’m glad we can mark this year as done, and I’m hoping and praying the next year is better.</p>\n<p>Until next time, stay safe, and may this new year be better than the last.</p>\n",
      "date_published": "2020-12-31T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/composing-data-in-eleventy/",
      "url": "https://www.falldowngoboone.com/blog/composing-data-in-eleventy/",
      "title": "Composing data in Eleventy",
      "content_html": "<p>A lot of what I do at <a href=\"https://www.containerstore.com/welcome.htm\">The Container Store</a> involves page templates, and one of the biggest challenges with template work (and components, for that matter) is creating a system that’s flexible yet maintainable. One of the ways flexibility can be achieved is by giving child elements a way to hook into the parent element. In JSP templates (what we use at The Container Store), template hooks can be added via <a href=\"https://www.oreilly.com/library/view/javaserver-pages-3rd/0596005636/re18.html\">the <code>invoke</code> action</a>, but I wanted to figure out how to do this on my personal Eleventy site.</p>\n<h2 id=\"the-use-case\" tabindex=\"-1\">The use case<a class=\"c-anchor-link\" href=\"#the-use-case\" aria-label=\"permalink\" aria-describedby=\"the-use-case\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I use <a href=\"https://prismjs.com\">Prism.js</a> to dynamically style my code blocks, and <a href=\"https://prismjs.com/#basic-usage\">the basic way to use Prism.js</a> relies on the presence of both a CSS file and a JavaScript file to be loaded on a page. The JavaScript adds classes to code blocks based on their type, and the CSS themes the blocks accordingly. The easiest (naive) way to include these assets in Eleventy is to add them directly to a global template:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- _includes/default.njk --></span><br><span class=\"token doctype\"><span class=\"token punctuation\">&lt;!</span><span class=\"token doctype-tag\">DOCTYPE</span> <span class=\"token name\">html</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>html</span> <span class=\"token attr-name\">lang</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>en<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>head</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">charset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>UTF-8<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>viewport<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>width=device-width, initial-scale=1.0<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>title</span><span class=\"token punctuation\">></span></span>{{ title }}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>title</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>{{ description }}<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/global.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token comment\">&lt;!-- Prism.js theme styles --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/prism-theme.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>head</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>body</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>o-page<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>header</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-header<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...header content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>header</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>main</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>main<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- render child content --></span><br>      {{ content | safe }}<br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>main</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>footer</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-footer<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...footer content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>footer</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token comment\">&lt;!-- Prism.js JavaScript --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/js/prism.js<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>body</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>html</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>In my case, I have two child templates based off of my global template, <code>_includes/page.njk</code>, which is the template for simple pages, and <code>_includes/post.njk</code>, the template for all of my blog posts. Since both are children of the global template, both receive the Prism.js JavaScript and CSS, even though only the post template will ever need it. We could move the script and CSS to the post template:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- _includes/post.njk --></span><br>---<br>layout: default<br>---<br><br><span class=\"token comment\">&lt;!-- Prism.js theme styles --></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/prism-theme.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span>{{ title }}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><br>{{ content | safe }}<br><span class=\"token comment\">&lt;!-- Prism.js JavaScript --></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/js/prism.js<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>The problem is the child templates render in the middle of the final page structure, meaning the <code>link</code> and <code>script</code> tags would render inside the <code>main</code> element:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- rendered post --></span><br><span class=\"token doctype\"><span class=\"token punctuation\">&lt;!</span><span class=\"token doctype-tag\">DOCTYPE</span> <span class=\"token name\">html</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>html</span> <span class=\"token attr-name\">lang</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>en<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>head</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">charset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>UTF-8<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>viewport<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>width=device-width, initial-scale=1.0<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>title</span><span class=\"token punctuation\">></span></span>The page title<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>title</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>The page description<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/global.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>head</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>body</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>o-page<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>header</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-header<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...header content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>header</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>main</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>main<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- Prism.js theme styles --></span><br>      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/prism-theme.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span>The page title<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><br>      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>...template content...<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- Prism.js JavaScript --></span><br>      <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/js/prism.js<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>main</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>footer</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-footer<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...footer content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>footer</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>body</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>html</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>While technically this works, it’s not optimal. Ideally, we want all stylesheets to render in the document <code>head</code> and all scripts to render just before the closing <code>body</code> tag, both of which are outside the scope of the child templates.</p>\n<h2 id=\"using-extends\" tabindex=\"-1\">Using <code>extends</code><a class=\"c-anchor-link\" href=\"#using-extends\" aria-label=\"permalink\" aria-describedby=\"using-extends\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The template language I’m using is <a href=\"https://mozilla.github.io/nunjucks/\">Nunjucks</a>, which, as luck would have it, has a built-in way to do this using <a href=\"https://mozilla.github.io/nunjucks/templating.html#extends\"><code>extends</code></a>:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- _includes/default.njk --></span><br><br><span class=\"token doctype\"><span class=\"token punctuation\">&lt;!</span><span class=\"token doctype-tag\">DOCTYPE</span> <span class=\"token name\">html</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>html</span> <span class=\"token attr-name\">lang</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>en<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>head</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">charset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>UTF-8<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>viewport<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>width=device-width, initial-scale=1.0<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>title</span><span class=\"token punctuation\">></span></span>The page title<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>title</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>The page description<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/global.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  {% block head %}{% endblock %}<br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>head</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>body</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>o-page<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>header</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-header<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...header content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>header</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>main</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>main<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      {% block content %}{% endblock %}<br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>main</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>footer</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-footer<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...footer content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>footer</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  {% block script %}{% endblock %}<br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>body</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>html</span><span class=\"token punctuation\">></span></span></code></pre>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- _includes/post.njk --></span><br><br><span class=\"token comment\">&lt;!-- absolute paths in `extends` resolve to the `_includes` directory --></span><br>{% extends \"default.njk\" %}<br><br>{% block head %}<br><span class=\"token comment\">&lt;!-- Prism.js theme styles --></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/prism-theme.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>{% endblock %}<br><br>{% block content %}<br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span>The page title<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>p</span><span class=\"token punctuation\">></span></span>...template content...<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>p</span><span class=\"token punctuation\">></span></span><br>{% endblock %}<br><br>{% block script %}<br><span class=\"token comment\">&lt;!-- Prism.js JavaScript --></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/js/prism.js<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span><br>{% endblock %}</code></pre>\n<p>This works in Eleventy, but not without limitations.</p>\n<p>First of all, Eleventy won’t process <a href=\"https://www.11ty.dev/docs/data-frontmatter/\">front matter</a> in templates that use <code>extends</code>, and no aliases set in Eleventy’s configuration will be used in resolving <code>include</code> paths (alternatively you may use <a href=\"https://www.11ty.dev/docs/languages/nunjucks/#supported-features\">relative paths</a>). Second, it locks the project into Nunjucks. One of the things I love about Eleventy is how easily I can change template languages out, but now I <em>have</em> to use Nunjucks. I mean, I like Nunjucks, but, even more so, I like having options.</p>\n<h2 id=\"using-front-matter\" tabindex=\"-1\">Using front matter<a class=\"c-anchor-link\" href=\"#using-front-matter\" aria-label=\"permalink\" aria-describedby=\"using-front-matter\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>If you want a child-specific value available to a parent template, you have to specify it in that page’s front matter. We can use this as a way to pass blocks of content up the template chain. I’m going to add two new keys to the front matter, <code>headContent</code> and <code>scriptContent</code>, and render them in the parent template document:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- _includes/post.njk --></span><br>---<br>layout: default<br>headContent: |<br>  <span class=\"token comment\">&lt;!-- Prism.js theme styles --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/prism-theme.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>scriptContent |<br>  <span class=\"token comment\">&lt;!-- Prism.js JavaScript --></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/js/prism.js<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span><br>---<br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span>{{ title }}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><br>{{ content | safe }}</code></pre>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- _includes/default.njk --></span><br><br><span class=\"token doctype\"><span class=\"token punctuation\">&lt;!</span><span class=\"token doctype-tag\">DOCTYPE</span> <span class=\"token name\">html</span><span class=\"token punctuation\">></span></span><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>html</span> <span class=\"token attr-name\">lang</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>en<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>head</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">charset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>UTF-8<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>viewport<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>width=device-width, initial-scale=1.0<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>title</span><span class=\"token punctuation\">></span></span>The page title<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>title</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>The page description<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/global.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>  {{ headContent }}<br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>head</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>body</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>o-page<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>header</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-header<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...header content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>header</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>main</span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>main<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      {{ content | safe }}<br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>main</span><span class=\"token punctuation\">></span></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>footer</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>c-footer<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br>      <span class=\"token comment\">&lt;!-- ...footer content --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>footer</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span><br>  {{ scriptContent }}<br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>body</span><span class=\"token punctuation\">></span></span><br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>html</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Notice the pipe character (<code>|</code>) in the front matter definition. This defines the style of a <a href=\"https://yaml.org/spec/1.2/spec.html#id2793652\">block scalar</a> in <a href=\"https://yaml.org\">YAML</a> (the language the front matter is written in) to keep line breaks. An alternative to this approach would be to pass a list of paths for each key, but I want the flexibility to inline scripts and styles as well:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- some-post.njk --></span><br>---<br>layout: post<br>headContent: |<br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>style</span><span class=\"token punctuation\">></span></span><span class=\"token style\"><span class=\"token language-css\"><br>    <span class=\"token selector\">.custom-page-style</span> <span class=\"token punctuation\">{</span><br>      <span class=\"token comment\">/* your custom styles here */</span><br>    <span class=\"token punctuation\">}</span><br>  </span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>style</span><span class=\"token punctuation\">></span></span><br>scriptContent: |<br>  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span><span class=\"token punctuation\">></span></span><span class=\"token script\"><span class=\"token language-javascript\"><br>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"I'm a custom page script\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  </span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span><br>---<br><br><span class=\"token comment\">&lt;!-- page content --></span></code></pre>\n<p>However, there’s a problem with the code above. Can you see it? It’s re-defining the <code>headContent</code> and <code>scriptContent</code> keys in the front matter, and according to the <a href=\"https://www.11ty.dev/docs/data-frontmatter/\">Eleventy front matter data documentation</a>, “locally assigned front matter values override things further up the layout chain.” The page content blocks are clobbering template content blocks, which means the Prism.js assets aren’t being loaded on this page.</p>\n<h2 id=\"composing-data-with-eleventycomputed\" tabindex=\"-1\">Composing data with <code>eleventyComputed</code><a class=\"c-anchor-link\" href=\"#composing-data-with-eleventycomputed\" aria-label=\"permalink\" aria-describedby=\"composing-data-with-eleventycomputed\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>We can fix the front matter key collision issue a couple of ways.</p>\n<p>First, we could create a second template hook that only pages would use (e.g. <code>pageHeadContent</code>). That could work, but what if we want to extend the post layout template with another layout template that needs to add custom styles and scripts? Also, it’s still possible for a page to accidentally overwrite the <code>headContent</code> in front matter. This isn’t an issue on small sites, but maybe you’re building a sharable theme or you’re working with a constantly changing team.</p>\n<p>Ideally what we want is some way to compose all of the <code>headContent</code> data into a single block. That way we don’t have to worry about what key to use in the current layout we are in. That brings us to our second option, which is using Eleventy’s <a href=\"https://www.11ty.dev/docs/data-computed/\">computed data</a>.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- _includes/post.njk --></span><br>---<br>layout: default<br>eleventyComputed:<br>  headContent: |<br>    <span class=\"token comment\">&lt;!-- Prism.js theme styles --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>stylesheet<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/css/prism-theme.css<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br>    {{ headContent }}<br>  scriptContent: |<br>    <span class=\"token comment\">&lt;!-- Prism.js JavaScript --></span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/js/prism.js<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span><br>    {{ scriptContent }}<br>---<br><br><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>h1</span><span class=\"token punctuation\">></span></span>{{ title }}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>h1</span><span class=\"token punctuation\">></span></span><br>{{ content | safe }}</code></pre>\n<p><code>eleventyComputed</code> is a special Eleventy front matter key that grants access to the computed data at the time of rendering the individual page. This is how we can pass data from leaf templates up the layout template chain, allowing us to effectively extend leaf data with template data. Notice the leaf data is included at the end of the template block. This ensures the leaf styles have higher order specificity in the style cascade and leaf scripts can override template scripts if needed.</p>\n<p>Now we have composable blocks of code that allow us to tie into the base template and extend the page with whatever functionality or styling we want. This is a great example of how powerful Eleventy can be, even though the basic concepts are so simple.</p>\n<h2 id=\"ideas-for-further-exploration\" tabindex=\"-1\">Ideas for further exploration<a class=\"c-anchor-link\" href=\"#ideas-for-further-exploration\" aria-label=\"permalink\" aria-describedby=\"ideas-for-further-exploration\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>We’ve explored how to optimize assets in Eleventy templates using composable <code>eleventyComputed</code> values. You can easily adapt this idea to add custom art direction, animations or behavior to an individual page, but this is something that has even more uses outside of styles and scripts.</p>\n<p>I hope this inspires you to explore more interesting uses of Eleventy’s computed data. And if you have a favorite Eleventy tip, <a href=\"https://twitter.com/therealboone\">tell me about it on Twitter</a>!</p>\n",
      "date_published": "2020-11-28T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/how-im-redesigning-my-blog/",
      "url": "https://www.falldowngoboone.com/blog/how-im-redesigning-my-blog/",
      "title": "How I&#39;m redesigning my blog",
      "content_html": "<p>Personal projects are a great way to grow your skillset, learn new technologies and explore new ideas. I began my personal blog with that in mind, but also wanted to share what I learn. With that in mind, I wanted to try and document the process behind this new redesign.</p>\n<p>I began this current redesign almost immediately after finishing my last redesign. My original plan was to launch a default Gatsby starter blog and then incrementally redesign it. That did not go as planned.</p>\n<p>Difficulties with Gatsby conventions (like using the GraphQL data mesh layer and MDX weirdness) and a growing concern over build performance led me to eventually abandon the framework. I spent the next year or so trying out different tools and tweaking design decisions, until I landed on what you see here.</p>\n<h2 id=\"the-design\" tabindex=\"-1\">The Design<a class=\"c-anchor-link\" href=\"#the-design\" aria-label=\"permalink\" aria-describedby=\"the-design\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>As I write this, the design and build out are not complete, but I’ve decided to launch what I have so far. Why? I have confidence that getting the design out into the real world will help me iterate on it quicker, and I can easily see which ideas have value and which do not. With that said, here are some highlights of the design.</p>\n<h3 id=\"inspiration\" tabindex=\"-1\">Inspiration<a class=\"c-anchor-link\" href=\"#inspiration\" aria-label=\"permalink\" aria-describedby=\"inspiration\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>I have always been a fan of the <a href=\"https://en.wikipedia.org/wiki/International_Typographic_Style\">Swiss Style</a>, so I knew I wanted to incorporate a strong grid with a grotesque typeface. The grid on the blog pages is based on the Golden Ratio, with the main block on wide displays being roughly 0.618 times the width of the full grid. The text blocks are limited in line length using <code>ch</code> units, which equal the width of a font’s <code>0</code> character.</p>\n<p>Breaking with the Swiss Style, and as an homage to the <a href=\"https://en.wikipedia.org/wiki/A_Gruesome_Twosome\">cartoons that inspired this blog’s name</a>, I wanted to include hand-drawn illustrations and decoration, just so the site itself didn’t end up feeling too cold or rigid.</p>\n<figure>\n  <img width=\"810\" height=\"535\" srcset=\"assets/sketches@1x.png 1x, assets/sketches@2x.png 2x\" src=\"assets/sketches@1x.png\" alt=\"\">\n  <figcaption>Initial sketches of hand-drawn element ideas</figcaption>\n</figure>\n<p>My process has been sketching out ideas on paper first, then moving into Figma or Affinity Designer for high fidelity exploration. I’ve tried to move to designing in the browser as quickly as possible because that’s the medium the design will ultimately end up in. If I run into a design roadblock in the browser, I return to Figma or Affinity Designer and explore some more.</p>\n<figure>\n  <img width=\"810\" height=\"506\" srcset=\"assets/figma-experiments@1x.png 1x, assets/figma-experiments@2x.png 2x\" src=\"assets/figma-experiments@1x.png\" alt=\"\">\n  <figcaption>Design exploration in Figma</figcaption>\n</figure>\n<h3 id=\"fonts\" tabindex=\"-1\">Fonts<a class=\"c-anchor-link\" href=\"#fonts\" aria-label=\"permalink\" aria-describedby=\"fonts\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>I love geometric typefaces, but they tend to be cold. Since I have hand-drawn elements, I wanted something with a bit more warmth. <a href=\"https://www.myfonts.com/fonts/tipotype/rotunda/\">Rotunda</a> filled the role perfectly, with a mix of geometric and humanistic forms. Oh, and I’m a sucker for double-story 'g’s and 'a’s.</p>\n<figure>\n  <img width=\"810\" height=\"287\" srcset=\"assets/rotunda@1x.png 1x, assets/rotunda@2x.png 2x\" src=\"assets/rotunda@1x.png\" alt=\"\">\n  <figcaption>Rotunda has humanistic forms as well as geometric alternates</figcaption>\n</figure>\n<p>I’m using Rotunda almost exclusively for headings, and for the body copy I’m opting for a simple <a href=\"https://css-tricks.com/snippets/css/system-font-stack/\">system font stack</a>. I’m still weighing the cost/benefit of using Rotunda for body copy as well. I’m trying to be somewhat conservative with the page weight.</p>\n<h3 id=\"animated-gradient-links\" tabindex=\"-1\">Animated gradient links<a class=\"c-anchor-link\" href=\"#animated-gradient-links\" aria-label=\"permalink\" aria-describedby=\"animated-gradient-links\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>One element of this design I really like, heavily inspired by CSS-Tricks, is the animated gradient link hover style. The effect is achieved using an oversized background gradient clipped to the text with <code>background-clip: text</code>. The only thing that’s animated is the <code>background-position</code>.</p>\n<p>There’s some <code>box-decoration-break</code> magic that makes sure the background style translates properly across line breaks, and <code>-webkit-text-fill-color: transparent</code> is needed to hide the text color.</p>\n<p class=\"codepen\" data-height=\"500\" data-theme-id=\"dark\" data-default-tab=\"css,result\" data-user=\"falldowngoboone\" data-slug-hash=\"MWeXqoy\" style=\"height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"Gradient animation on hover\">\n  <span>See the Pen <a href=\"https://codepen.io/falldowngoboone/pen/MWeXqoy\">\n  Gradient animation on hover</a> by Ryan Boone (<a href=\"https://codepen.io/falldowngoboone\">@falldowngoboone</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://static.codepen.io/assets/embed/ei.js\"></script>\n<h2 id=\"the-stack\" tabindex=\"-1\">The Stack<a class=\"c-anchor-link\" href=\"#the-stack\" aria-label=\"permalink\" aria-describedby=\"the-stack\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<h3 id=\"eleventy-and-liquid-nunjucks\" tabindex=\"-1\">Eleventy and <s>Liquid</s> Nunjucks<a class=\"c-anchor-link\" href=\"#eleventy-and-liquid-nunjucks\" aria-label=\"permalink\" aria-describedby=\"eleventy-and-liquid-nunjucks\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>The new design is completely static and built with <a href=\"https://www.11ty.dev\">Eleventy</a>. I’ve chosen Eleventy to replace my previous framework of Gatsby mainly because of Eleventy’s flexibility and ease of use. Eleventy is also a great deal faster than Gatsby, though my site is so small that I’ve barely noticed a difference when building.</p>\n<p><s>My template language of choice is Liquid, which, to be honest, I’m rethinking. The syntax can be quite awkward at times (possibly because of its Ruby origins). For example, empty strings in Liquid are truthy values, as opposed to JavaScript, where they are falsy, so in cases where you can either have a falsy value or an empty string, you must check for both. This is something that could be solved with something like a custom filter, but it’s quite annoying, and certainly not the only quirk this template language has.</s></p>\n<p><strong>Update:</strong> Yeah, so, I’m not using Liquid anymore. The biggest reason is a practical one: the syntax highlighting and language support has been a constant pain to manage in VS Code. I’ve been using the <a href=\"https://marketplace.visualstudio.com/items?itemName=sissel.shopify-liquid\">Liquid VS Code extension</a>, which I’ve had to completely disable due to an incident where it fried some source code at work (long story short, there’s a bug that causes it to encode certain tokens that unknowingly rewrote a large portion of some JSP templates). Even before that, it wasn’t that great of an extension. The author is supposedly rewriting it into a freemium extension called <a href=\"https://github.com/panoply/vscode-liquid/issues/56\">Liquify</a>, but I’m not terribly interested.</p>\n<p>To be honest, using Liquid at this point feels like swimming upstream. I’ve switched to Nunjucks, and already I feel less tension with my editor. I was able to convert everything over in an hour or so. I won’t tell you how long it took me to convert over to Liquid.</p>\n<h3 id=\"modern-css\" tabindex=\"-1\">Modern CSS<a class=\"c-anchor-link\" href=\"#modern-css\" aria-label=\"permalink\" aria-describedby=\"modern-css\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>CSS has been going through a layout renaissance over the past few years, and I have been keen to explore some <a href=\"https://aneventapart.com/news/post/designing-intrinsic-layouts-aea-video\">Intrinsic Web Design</a> techniques. In particular, I wanted to avoid screen width media queries as much as possible. And as I’m working toward that goal, I’ve been using this site to get better acquainted with <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout\">CSS Grid</a>.</p>\n<p>I’m also using some <a href=\"https://css-tricks.com/snippets/css/fluid-typography/\">fluid typography</a>, as well as the shiny new <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/clamp\"><code>clamp</code></a> function. I should note that fluid typography utilizes viewport units, which breaks custom default values for users. For that reason, I’ve limited the fluid typography to the page title and site spacing.</p>\n<p>Of course, this wouldn’t be modern CSS without a good dose of custom properties. I’m trying to use property names that are more representational of their use and not their description (e.g. <code>--color-main</code> instead of <code>--color-black</code>). This should make it easier for theming in the future for things like a “dark mode.”</p>\n<pre class=\"language-scss\"><code class=\"language-scss\"><span class=\"token selector\">:root </span><span class=\"token punctuation\">{</span><br>  <span class=\"token property\">--color-main</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">#{$color-black}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--color-secondary</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">#{$color-gray-700}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--color-bg</span><span class=\"token punctuation\">:</span> white<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--color-bg-secondary</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">#{$color-gray-200}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--color-border</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">#{$color-gray-500}</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token property\">--link-color</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">#{$color-purple}</span><span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--title-color</span><span class=\"token punctuation\">:</span> <span class=\"token variable\">#{$color-purple}</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token property\">--code-bg</span><span class=\"token punctuation\">:</span> #fffafb<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--code-color</span><span class=\"token punctuation\">:</span> #e2003a<span class=\"token punctuation\">;</span><br>  <span class=\"token property\">--code-border</span><span class=\"token punctuation\">:</span> #ffe7ed<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Finally, I’m following the <a href=\"https://www.xfive.co/blog/itcss-scalable-maintainable-css-architecture/\">ITCSS</a> way of organization for all of my styles. If given the choice, it’s my preferred methodology. I think the concept of going from wide usage and weak specificity toward very specific, focused styles best represents my mental model of CSS.</p>\n<h3 id=\"dart-sass\" tabindex=\"-1\">Dart Sass<a class=\"c-anchor-link\" href=\"#dart-sass\" aria-label=\"permalink\" aria-describedby=\"dart-sass\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>This is the first project where I have fully embraced <a href=\"https://sass-lang.com/dart-sass\">Dart Sass</a> over <a href=\"https://www.npmjs.com/package/node-sass\"><code>node-sass</code></a>. There are a few reasons for this.</p>\n<p>First of all, Dart Sass has the latest and greatest Sass goodies, like <a href=\"https://sass-lang.com/blog/the-module-system-is-launched\">Sass modules</a>, which offer a superior experience for limiting the scope of modules and optimizing imports. I personally like the explicitness of creating namespaces so you know what file that magical mixin came from.</p>\n<p>Second, in case you haven’t heard, <a href=\"https://github.com/sass/libsass/issues/3123\">LibSass is being deprecated</a>. It seems Dart Sass will soon be the only supported implementation of Sass. LibSass has been known for its superior speed (an advantage it still has over the JavaScript bindings for Dart Sass), but it has also been plagued with a slow development cycle.</p>\n<p>This slow development cycle means LibSass can’t even keep up with the CSS spec. If you attempt to use the <code>max</code> or <code>min</code> functions as they are supported in CSS, you will receive an error due to Sass’s history with these functions. <a href=\"https://css-tricks.com/when-sass-and-new-css-features-collide/\">There are workarounds for this and other issues</a>, but I prefer not to bother with them.</p>\n<h3 id=\"netlify\" tabindex=\"-1\">Netlify<a class=\"c-anchor-link\" href=\"#netlify\" aria-label=\"permalink\" aria-describedby=\"netlify\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>Finally, in order to get my site to you, I’m using <a href=\"https://www.netlify.com\">Netlify</a>. There’s nothing really special about my deployment configuration; it’s basically the configuration file that Eleventy generates. The only difference is I’m generating the Sass at build time as well.</p>\n<p>Something to note: when I first deployed the new site, I kept getting a build error. It looked like there was a process that wasn’t ending properly. Turns out my the <code>clean</code> script I had added to the <code>build</code> was the culprit. I’ve patched up the issue by creating a separate build step for production only.</p>\n<p>I think eventually I would like to write a custom build script, one that relies on environment variables to do things like watch for changes or clean build files. This is something I’ve been trying to work towards in my work on The Container Store website’s front end tooling, and this would be a great place to try some different ideas out.</p>\n<h3 id=\"metrics\" tabindex=\"-1\">Metrics<a class=\"c-anchor-link\" href=\"#metrics\" aria-label=\"permalink\" aria-describedby=\"metrics\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>One reason people tend to pick static site generators is performance, so how does my site perform? It depends on what day you’re auditing the site. I’m still tweaking some of my Lighthouse scores, but performance is coming out to a score of 100. Honestly, my Gatsby site had the same score (again, this is not a big site at the moment, and it’s mostly text).</p>\n<figure>\n  <img width=\"810\" height=\"430\" srcset=\"assets/metrics@1x.png 1x, assets/metrics@2x.png 2x\" src=\"assets/metrics@1x.png\" alt=\"Performance 100, Accessibility 90, Best Practices 100, SEO 92\">\n  <figcaption>Site metrics in Lighthouse at original publish date (November 15, 2020)</figcaption>\n</figure>\n<p>Some things I need to work on are SEO and some annoying duplicate ID issues that are dinging me on my Accessibility score. Ultimately, the goal is to get to 100 in all categories, and hopefully I’ll get there by the time people are reading this post.</p>\n<p><strong>Update:</strong> The last few issues have been corrected and now I’m getting all 100s!</p>\n<figure>\n  <img width=\"810\" height=\"322\" srcset=\"assets/metrics-updated@1x.png 1x, assets/metrics-updated@2x.png 2x\" src=\"assets/metrics-updated@1x.png\" alt=\"Performance 100, Accessibility 100, Best Practices 100, SEO 100\">\n  <figcaption>Updated site metrics in Lighthouse on November 16, 2020</figcaption>\n</figure>\n<h2 id=\"the-future\" tabindex=\"-1\">The Future<a class=\"c-anchor-link\" href=\"#the-future\" aria-label=\"permalink\" aria-describedby=\"the-future\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So, I am by no means done with the site. My future plans are to add a contact form that utilizes Netlify forms, add an About page with some more detail about me, and add a bookshelf section that shows what I’ve been reading. In terms of features, I’d like to integrate my Twitter feed into the home page to show my latest TIL (today I learned) tweet, add site-wide messaging, finish the home page layout, and possibly switch from Liquid templates to Vue via <a href=\"https://www.netlify.com/blog/2020/09/18/eleventy-and-vue-a-match-made-to-power-netlify.com/\">Eleventy’s experimental Vue support</a>.</p>\n<p>I also want to incorporate more design elements I just haven’t been able to get to, like adding animations and more hand-drawn visuals. I want to be considerate of site performance as well, so I’m cautiously experimenting with different approaches.</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion<a class=\"c-anchor-link\" href=\"#conclusion\" aria-label=\"permalink\" aria-describedby=\"conclusion\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>So that’s a short overview of my blog’s redesign. I promise there’s more to come, but my ultimate goal is to push past my tendency for perfectionism. You can’t share what you’re doing if you wait for perfection. I hope this has been helpful in some way to you.</p>\n<p>Are you in the middle of designing and/or building your own personal project? I want to hear from you. Do you have any questions about my process or the stack I’m using? I want to hear from you, too.</p>\n<p>Until next time!</p>\n",
      "date_published": "2020-11-15T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/accessibility-is-hard/",
      "url": "https://www.falldowngoboone.com/blog/accessibility-is-hard/",
      "title": "Accessibility is hard, but we can do better",
      "content_html": "<p>Recently I made the trek to New York City to attend SmashingConf. A recurring theme this year was accessibility, and for good reason. The Domino’s Pizza case has been trending in the Front End Dev community for a while now, and I’ve been preoccupied with accessibility as of late as well, due to circumstances surrounding my current place of employment (I think this would be a good time to state that my opinions expressed are solely my own and do not express the views or opinions of my employer, blah, blah, blah).</p>\n<p>While I was in New York, I read Robin Rindle’s CSS-Tricks article <a href=\"https://css-tricks.com/why-are-accessible-websites-so-hard-to-build/\">Why Are Accessible Websites so Hard to Build</a>, and I think it helps bring to light one of the common misconceptions about corporations and the lack of accessible websites. If I were to sum up my belief why accessible websites are difficult to make, it would be ignorance.</p>\n<h2 id=\"i-am-an-idiot\" tabindex=\"-1\">I am an idiot<a class=\"c-anchor-link\" href=\"#i-am-an-idiot\" aria-label=\"permalink\" aria-describedby=\"i-am-an-idiot\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I remember taking on the task of making an existing web feature accessible, something that I thought in theory I could do rather easily, but it wasn’t until I started to use (or <em>try</em> to use) accessibility tools like VoiceOver that I realized how unequipped I was. To top it off, the entire design and implementation of the feature made it close to impossible to simply bolt accessibility on top (disclosure: I’m the one that built it in the first place. 🤦‍♂️).</p>\n<p>This was just one feature. And I thought I initially built it to <em>be</em> accessible. My problem was I had no idea how to confirm my assumptions, nor had I not been instructed on how to test for accessibility. I simply wrote semantic markup and thought that was enough. It was not.</p>\n<p>Now imagine a monolithic website created over the course of ten years by dozens of developers, most of whom never even thought about accessibility, and most of whom are no longer with the company. This is what most legacy retail sites are working with.</p>\n<h2 id=\"lawsuits-are-not-the-solution\" tabindex=\"-1\">Lawsuits are not the solution<a class=\"c-anchor-link\" href=\"#lawsuits-are-not-the-solution\" aria-label=\"permalink\" aria-describedby=\"lawsuits-are-not-the-solution\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>According to a <a href=\"https://blog.usablenet.com/2018-ada-web-accessibility-lawsuit-recap-report\">2018 report from UsableNet</a>, an independent, full-service accessibility agency, accessibility-related website lawsuits increased from 814 in 2017 to 2,285 in 2018, up 181%. This report states that even companies proactive in making their sites accessible have been targets of these lawsuits.</p>\n<p>Rindle in his aforementioned article says his personal hope is that “[these lawsuits] will get folks to care more about semantics and front-end development best practices.” I don’t believe they will. I think they will merely propagate a cat and mouse game between lawyers and corporations where a business will fix one thing only to be called out on another thing that <em>could</em> be interpreted as inaccessible.</p>\n<p>The sad reality is the only people that seem to be getting anything out of these lawsuits are the plaintiff and defendant lawyers. They get paid regardless.</p>\n<h2 id=\"regulation-is-part-of-the-solution\" tabindex=\"-1\">Regulation is part of the solution<a class=\"c-anchor-link\" href=\"#regulation-is-part-of-the-solution\" aria-label=\"permalink\" aria-describedby=\"regulation-is-part-of-the-solution\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>The basis of these recent lawsuits is the Americans with Disabilities Act, specifically Title III, which “directs [private places of public accommodation] to make ‘reasonable modifications’ to their usual ways of doing things when serving people with disabilities” and also “take steps necessary to communicate effectively with customers with vision, hearing, and speech disabilities” (<a href=\"https://adata.org/learn-about-ada\">source</a>).</p>\n<p>The ADA became law in 1990, so websites weren’t even considered. There have been several judgements regarding websites as places of public accommodation, all with mixed decisions. To this day, Congress has done little in the way of addressing how to define accessibility with regards to websites, let alone even specifically including websites in the ADA. This, in my opinion, is the number one problem we have right now.</p>\n<p>There is some guidance as a result of trial decisions that point to <a href=\"https://www.w3.org/TR/WCAG20/\">WCAG 2.0 level AA</a> (<a href=\"https://www.w3.org/TR/WCAG21/\">2.1</a> is the latest) as the gold standard of accessibility, but <a href=\"https://www.adatitleiii.com/wp-content/uploads/sites/121/2018/10/DOJ-letter-to-congress.pdf\">a 2018 letter from Assistant Attorney General Stephen E. Boyd</a> seems to suggest that WCAG is not necessarily the baseline for accessibility, stating that “public accommodations have flexibility in how to comply with the ADA’s general requirements of nondiscrimination and effective communication.” This letter, which was written in response to a bipartisan Congressional letter, basically told Congress that they needed to provide more clarity through legislation.</p>\n<h2 id=\"what-we-need\" tabindex=\"-1\">What we need<a class=\"c-anchor-link\" href=\"#what-we-need\" aria-label=\"permalink\" aria-describedby=\"what-we-need\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>It is my personal belief that Congress needs to clarify that websites are indeed covered by Title III of the ADA, and with that, Congress needs to provide clear direction of a standard that websites must adhere to (I’m personally in favor of WCAG). I also would like to see the ADA applied to non-brick-and-mortar websites as well. Then entire web needs to held to the same standard.</p>\n<p>I also believe there needs to be an official website accessibility certification process that large corporations must go through annually, provided by an independent third-party auditor. Non-compliance would require a business to submit a plan that must be enacted within a reasonable amount of time, during which a company would be immune to Title III related litigation.</p>\n<p>Failure to meet the timeline would result in fees, which would go toward policing legislation and accessibility advocacy.</p>\n<h2 id=\"what-we-can-do-today\" tabindex=\"-1\">What we can do today<a class=\"c-anchor-link\" href=\"#what-we-can-do-today\" aria-label=\"permalink\" aria-describedby=\"what-we-can-do-today\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>In short, we need to build accessible websites. We need to do better as developers being advocates for minorities. We need to do better as an industry with hiring QA and developers with special needs. Perspective and empathy are invaluable tools to build a better web.</p>\n<p>I hope to write more in the future about what I’m doing at The Container Store to promote accessibility, as well as future accessibility wins. If nothing else, my hope is that my co-workers see accessibility as a necessity, not a feature. Ignorance is fought with awareness and empathy.</p>\n<p>If you agree (or even if you disagree) with anything I’ve said, <a href=\"https://mobile.twitter.com/search?q=https%3A%2F%2Fwww.falldowngoboone.com%2Fblog%2Faccessible-websites-and-the-evil-corporation\">let me know on Twitter</a>. And please write to your representative and let them know you want clarity on the protection of individuals with disabilities. Finally, be an advocate for accessibility where you are. Whether you are a developer or designer, you can make a difference where you are.</p>\n",
      "date_published": "2019-10-27T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/the-feedback-loop/",
      "url": "https://www.falldowngoboone.com/blog/the-feedback-loop/",
      "title": "The Feedback Loop",
      "content_html": "<p>Getting feedback fast is one of the most important things in development. What do I mean about feedback?</p>\n<p>Let’s imagine playing a video game. You have a console, a controller, and a screen. If you press left on the controller’s d-pad, your character walks to the left on the screen. If you press right on the d-pad, your character walks right. Makes sense, right?</p>\n<p>Of course, if you’ve ever used a sketch online video game service, you may be familiar with lag. Maybe you press right on your d-pad and your character waits a split second before walking to the right. Not terrible lag, but enough to notice. Maybe the lag’s even worse. Maybe you press right and nothing happens, then you press left and your character walks to the right. This is arguably not only going to affect your game, but also how you perceive the game.</p>\n<p>In video games, you’re used to immediate feedback. What you input into the controller gets translated immediately (at least perceptively) to the screen. This is one of the fundamental reasons certain video games are easy to pick up and learn. Any lag in this feedback loop makes learning incredibly difficult and frustrating.</p>\n<p>Now, instead of a screen and a controller, imagine a text editor and an open browser. It doesn’t take too much of an imagination to see the same rule applies to development.</p>\n<p>When I start a new project, the first thing I do is figure out how to establish a feedback loop. A good example of this is a project I’m currently working on. It involves consuming a SOAP service and marshalling the responses to Java objects so they are ultimately expressed as JSON to a JavaScript front end. You may have no idea what some of that means (at the beginning of last week, I didn’t either), but that’s why establishing a feedback loop early is so important. The more direct and immediate the feedback, the more confidence I can have in my experimentation with the code.</p>\n<p>The way I established a feedback loop in this case was to create a REST-ful endpoint on the Java app where I could <code>GET</code> arbitrary information. Then, after rigorous (and tedious) configuration on the SOAP service part, I began retrieving information and printing it to the screen.</p>\n<p>Is this the best feedback loop? Maybe, maybe not. The point is, it’s good enough for now. The more I work on this project, the better (hopefully) my feedback loop will get.</p>\n<p>Good feedback loops are important. If you’re new to coding, work on establishing a good feedback loop immediately. Learn to identify when you need more information, then learn how to get that information. Maybe it’s a well-placed <code>console.log</code>. Maybe it’s dumping the contents of an object to the screen. Whatever it is, make sure it gives you the most direct information in the quickest way possible.</p>\n",
      "date_published": "2019-09-29T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/container-component-pattern-using-context-and-hooks/",
      "url": "https://www.falldowngoboone.com/blog/container-component-pattern-using-context-and-hooks/",
      "title": "React Presentational and Container Components Using Context and Hooks",
      "content_html": "<p><strong>Updated:</strong> I’ve updated the code to export a named function, not an anonymous arrow function.</p>\n<p>When I first started using React, I learned about <a href=\"https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0\">Presentational and Container Components</a> from Dan Abramov. This pattern prescribed splitting UI into smart (container) components that encapsulated state and logic, and dumb (presentational) components that simply presented data in a styled manner. In general, the containers were class components that managed state and lifecycle methods, whereas presentational components were stateless function components.</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// List.js</span><br><br><span class=\"token comment\">// presentational component</span><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">List</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> items <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>styled-list<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token punctuation\">{</span><span class=\"token function\">Boolean</span><span class=\"token punctuation\">(</span>items<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">)</span> <span class=\"token operator\">&amp;&amp;</span><br>        items<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">item</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>styled-item<span class=\"token punctuation\">\"</span></span> <span class=\"token spread\"><span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>item<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// MovieContainer.js</span><br><br><span class=\"token comment\">// container component</span><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">MovieContainer</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">React<span class=\"token punctuation\">.</span>Component</span> <span class=\"token punctuation\">{</span><br>  state <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token literal-property property\">movies</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><br>  <span class=\"token keyword\">async</span> <span class=\"token function\">componentDidMount</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> movies <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> movieService<span class=\"token punctuation\">.</span><span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">setState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> movies <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><br>  <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">return</span> <span class=\"token keyword\">typeof</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>children <span class=\"token operator\">===</span> <span class=\"token string\">'function'</span><br>      <span class=\"token operator\">?</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span><span class=\"token function\">children</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>state<span class=\"token punctuation\">)</span><br>      <span class=\"token operator\">:</span> React<span class=\"token punctuation\">.</span>Children<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">movies</span><span class=\"token operator\">:</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>state<span class=\"token punctuation\">.</span>movies <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// MovieList.js</span><br><br><span class=\"token comment\">// put it together (children as function FTW!)</span><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">MovieList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">MovieContainer</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> movies <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">List</span></span> <span class=\"token attr-name\">items</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>movies<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">MovieContainer</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>This pattern both decouples views from logic and creates logic that is easily shared. If you need to represent albums as a list, replace <code>&lt;MovieContainer /&gt;</code> with <code>&lt;AlbumContainer /&gt;</code>. If you need to represent movies as a grid, replace <code>&lt;List /&gt;</code> with a <code>&lt;Grid /&gt;</code> component. This pattern is flexible and effective, but it was not without its problems.</p>\n<p>First of all, this pattern makes use of class components, which, at least in my experience, bring with them all sorts of developer pain (React specifically; I’m not above using classes when appropriate). Second of all, lifecycle methods tend to break up related logic, so the more complex your components become, any changes introduced significantly increase the chance of bugs.</p>\n<p>To address these problems (and <a href=\"https://reactjs.org/docs/hooks-intro.html#motivation\">more</a>), the React team introduced the Hooks API. Using Hooks, you can easily encapsulate complex logic without the use of class components. One result was the ability to have stateful function components.</p>\n<p>Now that we can move logic into custom hooks, we no longer need container components that control state for us. We can handle calls to these hooks inside the presentational components themselves.</p>\n<p>I pair the Context API with Hooks, particularly the <code>useContext</code> hook, to recreate the Presentational and Container Component pattern without any classes whatsoever:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// List.js</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">List</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> items <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">/* no changes */</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// MovieProvider.js</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> MovieContext <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">createContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useMovies</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> context <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">useContext</span><span class=\"token punctuation\">(</span>MovieContext<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>context<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Use inside context provider!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <span class=\"token keyword\">return</span> context<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">MovieProvider</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> children <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>movies<span class=\"token punctuation\">,</span> setMovies<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  React<span class=\"token punctuation\">.</span><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br>    <span class=\"token comment\">// you can't pass async functions to Hooks</span><br>    movieService<span class=\"token punctuation\">.</span><span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>setMovies<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>setMovies<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">MovieContext.Provider</span></span> <span class=\"token attr-name\">value</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>movies<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>children<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">MovieContext.Provider</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// MovieList.js</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">MovieList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> movies <span class=\"token operator\">=</span> <span class=\"token function\">useMovies</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">return</span> <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">List</span></span> <span class=\"token attr-name\">items</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>movies<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// You need to wrap the component with the context</span><br><span class=\"token comment\">// provider somewhere. Here we've exported a \"connected\"</span><br><span class=\"token comment\">// version already wrapped. Don't do this if you need</span><br><span class=\"token comment\">// to consume a single provider in multiple components.</span><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">ConnectedMovieList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">MovieProvider</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">MovieList</span></span> <span class=\"token punctuation\">/></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">MovieProvider</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>Note that the presentational <code>&lt;List /&gt;</code> component remains unchanged, but now we are grabbing the <code>movies</code> state from a custom hook and applying it directly to <code>&lt;List /&gt;</code> without the need for a child function. This ends up being so much more readable and, in my opinion, easier to follow compared to the original. The “Container” component becomes a combination of a context provider and hook.</p>\n<p>It doesn’t take much to imagine getting more types of state out of the <code>useMovies</code> hook, like a loading state or an error message in the case of service failure. When your state management becomes more complex, you can look at using the <code>useReducer</code> Hook in lieu of <code>useState</code>. In that case, it’s recommended you pass the resulting <code>dispatch</code> method down in a separate context:</p>\n<pre class=\"language-jsx\"><code class=\"language-jsx\"><span class=\"token comment\">// List.js</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">List</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> items <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">/* no changes */</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// MovieProvider.js</span><br><br><span class=\"token comment\">// now we have two contexts</span><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> MovieStateContext <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">createContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> MovieDispatchContext <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">createContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useMovieState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> state <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">useContext</span><span class=\"token punctuation\">(</span>MovieStateContext<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>context<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Use inside context provider!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useMovieDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">useContext</span><span class=\"token punctuation\">(</span>MovieDispatchContext<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>context<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Use inside context provider!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br>  <span class=\"token keyword\">return</span> dispatch<span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">function</span> <span class=\"token function\">MovieReducer</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">/* reducer logic in here */</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">const</span> initialState <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token literal-property property\">isLoading</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br>  <span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">,</span><br>  <span class=\"token literal-property property\">movies</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">MovieProvider</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> children <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>movieState<span class=\"token punctuation\">,</span> dispatch<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">useReducer</span><span class=\"token punctuation\">(</span>movieReducer<span class=\"token punctuation\">,</span> initialState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  React<span class=\"token punctuation\">.</span><span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">fetchMovies</span><span class=\"token punctuation\">(</span>dispatch<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>dispatch<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">MovieStateContext.Provider</span></span> <span class=\"token attr-name\">value</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>movieState<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">MovieDispatchContext.Provider</span></span> <span class=\"token attr-name\">value</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>dispatch<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>        </span><span class=\"token punctuation\">{</span>children<span class=\"token punctuation\">}</span><span class=\"token plain-text\"><br>      </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">MovieDispatchContext.Provider</span></span><span class=\"token punctuation\">></span></span><span class=\"token plain-text\"><br>    </span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">MovieStateContext.Provider</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// completely ripped off from Kent C. Dodds and Dan Abramov;</span><br><span class=\"token comment\">// now you can async await all the things!</span><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">fetchMovies</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">dispatch</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'pending'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token keyword\">const</span> movies <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> movieService<span class=\"token punctuation\">.</span><span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'success'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> movies <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'error'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> error<span class=\"token punctuation\">.</span>message <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token punctuation\">}</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token comment\">// MovieList.js</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">MovieList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> isLoading<span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">,</span> movies <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useMovies</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br>  <span class=\"token keyword\">return</span> isLoading <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">LoadingAnimation</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> error <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">Message</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>error<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">{</span>error<span class=\"token punctuation\">}</span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span><span class=\"token class-name\">Message</span></span><span class=\"token punctuation\">></span></span><br>  <span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><br>    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">List</span></span> <span class=\"token attr-name\">items</span><span class=\"token script language-javascript\"><span class=\"token script-punctuation punctuation\">=</span><span class=\"token punctuation\">{</span>movies<span class=\"token punctuation\">}</span></span> <span class=\"token punctuation\">/></span></span><br>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br><span class=\"token punctuation\">}</span><br><br><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">ConnectedMovieList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br>  <span class=\"token comment\">/* same as above */</span><br><span class=\"token punctuation\">}</span></code></pre>\n<p>This is pretty much how I structure my components now. The advantage of this pattern is that I can wrap components with providers that override state for use in Storybook or tests. I can also easily keep my styled presentational components separate from my logic.</p>\n<p>Of course, now you have the overhead of understanding how closures can affect your values in Hooks. Also, Hooks have a strict set of guidelines you have to adhere to (only call Hooks inside a component or other Hook, don’t call conditionally, don’t call in loops, etc.). But if you can accept that, you can enjoy fewer bugs and more sharable logic.</p>\n",
      "date_published": "2019-09-15T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/free-online-web-design-and-dev-books/",
      "url": "https://www.falldowngoboone.com/blog/free-online-web-design-and-dev-books/",
      "title": "Free Online Web Design and Development Books",
      "content_html": "<p>One of my favorite pastimes is reading. When I started out as a developer, I would read anything I could get my hands on. And, since I was cheap, I tried to find as many free books as I could. What follows is a list that I’ve accumulated over the past few years of fantastic, completely free material that has helped me grow as a developer.</p>\n<p>A quick note before I get started: If you like what you’re reading, consider either buying the original source material or making a donation to the author. When you do that, you are paving the way for even more publicly available, high-quality material. Okay, here’s the list!</p>\n<h2 id=\"web-design\" tabindex=\"-1\">Web Design<a class=\"c-anchor-link\" href=\"#web-design\" aria-label=\"permalink\" aria-describedby=\"web-design\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Software developers are designers by extension. We interpret (or sometimes ignore) what we are given by designers. If you want to become a better developer, I would argue you need to build empathy for good design.</p>\n<h3 id=\"atomic-design\" tabindex=\"-1\">Atomic Design<a class=\"c-anchor-link\" href=\"#atomic-design\" aria-label=\"permalink\" aria-describedby=\"atomic-design\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>When I grow up, I want to be Brad Frost. His material was heavily inspirational in my early freelance web design career. In <em>Atomic Design</em>, Brad introduces the concept of how to break a web design down into systems instead of pages. This is required reading for anyone who designs or develops design systems. This is one book I highly recommend buying.</p>\n<p><a href=\"http://atomicdesign.bradfrost.com/table-of-contents/\">Read <em>Atomic Design</em> by Brad Frost</a>.</p>\n<p><a href=\"https://shop.bradfrost.com\">Buy <em>Atomic Design</em> by Brad Frost</a>.</p>\n<h3 id=\"resilient-web-design\" tabindex=\"-1\">Resilient web design<a class=\"c-anchor-link\" href=\"#resilient-web-design\" aria-label=\"permalink\" aria-describedby=\"resilient-web-design\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>Jeremy Keith is a thought leader in the web design community. This book (beautifully designed for reading on a screen) is a call to embrace inclusivity in web design and development. This book, and anything written by Jeremy Keith, makes me want to be a better web developer.</p>\n<p><a href=\"https://resilientwebdesign.com\">Read <em>Resilient web design</em> by Jeremy Keith</a></p>\n<h3 id=\"the-shape-of-design\" tabindex=\"-1\">The Shape of Design<a class=\"c-anchor-link\" href=\"#the-shape-of-design\" aria-label=\"permalink\" aria-describedby=\"the-shape-of-design\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>Frank Chimero’s treatise on design is both beautiful and useful, whether in digital or printed form. You will come away from this book believing that, as software developers, we are uniquely positioned to build things that can shape the design of this world.</p>\n<p><a href=\"https://shapeofdesignbook.com\">Read <em>The Shape of Design</em> by Frank Chimero</a>.</p>\n<p><a href=\"https://buyolympia.com/Item/frank-chimero-the-shape-of-design-paperback\">Buy <em>The Shape of Design</em> by Frank Chimero</a>.</p>\n<h3 id=\"butterick%E2%80%99s-practical-typography\" tabindex=\"-1\">Butterick’s Practical Typography<a class=\"c-anchor-link\" href=\"#butterick%E2%80%99s-practical-typography\" aria-label=\"permalink\" aria-describedby=\"butterick%E2%80%99s-practical-typography\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>If you want to become a better frontend developer, you need to learn what makes for good typography. This resource by Matthew Butterick is an extensive journey through the core concepts of typography. Bookmark this and return to it frequently.</p>\n<p><a href=\"https://practicaltypography.com\">Read <em>Butterick’s Practical Typography</em> by Matthew Butterick</a>.</p>\n<p><a href=\"https://practicaltypography.com/how-to-pay-for-this-book.html\">Support Matthew Butterick</a>.</p>\n<h2 id=\"frontend-development\" tabindex=\"-1\">Frontend Development<a class=\"c-anchor-link\" href=\"#frontend-development\" aria-label=\"permalink\" aria-describedby=\"frontend-development\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<h3 id=\"learning-javascript-design-patterns\" tabindex=\"-1\">Learning JavaScript Design Patterns<a class=\"c-anchor-link\" href=\"#learning-javascript-design-patterns\" aria-label=\"permalink\" aria-describedby=\"learning-javascript-design-patterns\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>Addy Osmani is a developer at Google, and back in 2012 he wrote a book that completely jumpstarted my interest in JavaScript development. This book (revised in 2017 online only) introduces the idea of programming design patterns, what they are, why they’re useful, etc., and then shows how to implement some of them in JavaScript. The idea of design patterns in software ignited my imagination, and I haven’t stopped learning since. This is a useful book whether you are a beginner or a more advanced developer.</p>\n<p><a href=\"https://addyosmani.com/resources/essentialjsdesignpatterns/book/\">Read <em>Learning JavaScript Design Patterns</em> by Addy Osmani</a>.</p>\n<h3 id=\"eloquent-javascript\" tabindex=\"-1\">Eloquent JavaScript<a class=\"c-anchor-link\" href=\"#eloquent-javascript\" aria-label=\"permalink\" aria-describedby=\"eloquent-javascript\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>This is another book I was heavily inspired by early on in my developer career. Marjin Haverbeke’s introduction to JavaScript is thorough, with great example snippets you can interact with directly in the browser. If you are learning JavaScript, this is a great place to start. I would highly recommend buying this one to have around the house or office.</p>\n<p><a href=\"http://eloquentjavascript.net\">Read <em>Eloquent JavaScript</em> by Marjin Haverbeke</a></p>\n<p><a href=\"https://www.amazon.com/Eloquent-JavaScript-3rd-Introduction-Programming/dp/1593279507/ref=pd_lpo_sbs_14_t_0?_encoding=UTF8&amp;psc=1&amp;refRID=YYJ7CNMF752GH1JGDXC8\">Buy <em>Eloquent JavaScript</em> by Marjin Haverbeke</a></p>\n<h3 id=\"front-end-developer-handbook-(updated-yearly)\" tabindex=\"-1\">Front End Developer Handbook (updated yearly)<a class=\"c-anchor-link\" href=\"#front-end-developer-handbook-(updated-yearly)\" aria-label=\"permalink\" aria-describedby=\"front-end-developer-handbook-(updated-yearly)\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p><a href=\"https://frontendmasters.com\">Frontend Masters</a> is an online learning website that is known for their quality, up-to-date front end info, and starting in 2018, they started releasing these nice handbooks that highlight some current front end best practices. I highly recommend both the handbooks and Frontend Masters’ paid content.</p>\n<p><a href=\"https://frontendmasters.com/books/front-end-handbook/2019/\">Read <em>Front End Developer Handbook 2019</em></a></p>\n<h2 id=\"general-programming\" tabindex=\"-1\">General Programming<a class=\"c-anchor-link\" href=\"#general-programming\" aria-label=\"permalink\" aria-describedby=\"general-programming\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<h3 id=\"you-don%E2%80%99t-know-js\" tabindex=\"-1\">You Don’t Know JS<a class=\"c-anchor-link\" href=\"#you-don%E2%80%99t-know-js\" aria-label=\"permalink\" aria-describedby=\"you-don%E2%80%99t-know-js\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>JavaScript can be confusing and frustrating, but Kyle Simpson is here to help you make sense of it all. The <em>YDKJS</em> series focuses on one or two topics per book, and they are honestly the best place to start when you decide to take the JS plunge. Highly recommend you buy these babies (“Scope and Closures” and “this &amp; Object Prototypes” are required reading IMO), but they are totally free to read on GitHub. Oh, and it looks like a second edition is in the works.</p>\n<p><a href=\"https://github.com/getify/You-Dont-Know-JS/tree/1st-ed\">Read <em>You Don’t Know JS 1st Edition</em> by Kyle Simpson</a>.</p>\n<p><a href=\"http://www.ebooks.com/1993212/you-don-t-know-js-up-going/simpson-kyle/\">Buy <em>You Don’t Know JS: Up &amp; Going</em> by Kyle Simpson</a>.</p>\n<p><a href=\"https://www.ebooks.com/en-us/1647631/you-don-t-know-js-scope-closures/simpson-kyle/\">Buy <em>You Don’t Know JS: Scope &amp; Closures</em> by Kyle Simpson</a>.</p>\n<p><a href=\"https://www.ebooks.com/en-us/1734321/you-don-t-know-js-this-object-prototypes/simpson-kyle/\">Buy <em>You Don’t Know JS: this &amp; Object Prototypes</em> by Kyle Simpson</a>.</p>\n<p><a href=\"https://www.ebooks.com/en-us/1935541/you-don-t-know-js-types-grammar/simpson-kyle/\">Buy <em>You Don’t Know JS: Types &amp; Grammar</em> by Kyle Simpson</a>.</p>\n<p><a href=\"https://www.ebooks.com/en-us/1977375/you-don-t-know-js-async-performance/simpson-kyle/\">Buy <em>You Don’t Know JS: Async &amp; Performance</em> by Kyle Simpson</a>.</p>\n<p><a href=\"https://www.ebooks.com/en-us/2481820/you-don-t-know-js-es6-beyond/simpson-kyle/\">Buy <em>You Don’t Know JS: ES6 &amp; Beyond</em> by Kyle Simpson</a>.</p>\n<h3 id=\"functional-light-javascript\" tabindex=\"-1\">Functional-Light JavaScript<a class=\"c-anchor-link\" href=\"#functional-light-javascript\" aria-label=\"permalink\" aria-describedby=\"functional-light-javascript\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>Kyle Simpson knows JS, and he also knows functional programming. To prove it, he wrote a whole book about it. This book, squarely aimed at the beginner, effectively introduces the core concepts of functional programming, something I’m excited about. There’s even a <a href=\"https://frontendmasters.com/courses/functional-javascript-v3/\">Frontend Masters class</a> if you are so inclined.</p>\n<p><a href=\"https://12factor.net\">Read <em>Functional-Light JavaScript</em> by Kyle Simpson</a>.</p>\n<p><a href=\"http://fljsbook.com\">Buy <em>Functional-Light JavaScript</em> by Kyle Simpson</a>.</p>\n<h3 id=\"professor-frisby%E2%80%99s-mostly-adequate-guide-to-functional-programming\" tabindex=\"-1\">Professor Frisby’s Mostly Adequate Guide to Functional Programming<a class=\"c-anchor-link\" href=\"#professor-frisby%E2%80%99s-mostly-adequate-guide-to-functional-programming\" aria-label=\"permalink\" aria-describedby=\"professor-frisby%E2%80%99s-mostly-adequate-guide-to-functional-programming\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>Okay, this is definitely an advanced book. Functional programming is one of those concepts that takes a while to get, but in my opinion, it’s well worth it. This book introduces the core concepts of functional programming through the voice of Professor Frisby, a cute, unassuming badger that somehow learned to type and then get tenure at university. Later, the book gets super heady. I honestly struggled to finish, but the beginning stuff is gold.</p>\n<p><a href=\"https://github.com/MostlyAdequate/mostly-adequate-guide\">Read <em>Professor Frisby’s Mostly Adequate Guide to Functional Programming</em></a>.</p>\n<h2 id=\"software-architecture\" tabindex=\"-1\">Software Architecture<a class=\"c-anchor-link\" href=\"#software-architecture\" aria-label=\"permalink\" aria-describedby=\"software-architecture\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<h3 id=\"the-twelve-factor-app\" tabindex=\"-1\">The Twelve-Factor App<a class=\"c-anchor-link\" href=\"#the-twelve-factor-app\" aria-label=\"permalink\" aria-describedby=\"the-twelve-factor-app\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>I learned about <em>The Twelve Factor App</em> from <a href=\"https://twitter.com/iamagiantnerd\">David Ayers</a>, who was the Technology Director at the time I started at The Container Store. It piqued my curiosity regarding technical architecture, and now I’m actually starting understand some of it.</p>\n<p><a href=\"https://12factor.net\">Read <em>The Twelve-Factor App</em> by Adam Wiggins</a>.</p>\n<h3 id=\"programming-javascript-applications\" tabindex=\"-1\">Programming JavaScript Applications<a class=\"c-anchor-link\" href=\"#programming-javascript-applications\" aria-label=\"permalink\" aria-describedby=\"programming-javascript-applications\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h3>\n<p>This book by Eric Elliott is a bit long in the tooth (it was published in the ancient year of 2014), but it’s filled with super-useful, still-relevant architectural concepts for building applications that go well beyond the world of JavaScript. Just know this is not a book for beginners. Try reading this after you have a few projects under the belt.</p>\n<p><a href=\"https://www.oreilly.com/library/view/programming-javascript-applications/9781491950289/\">Read <em>Programming JavaScript Applications</em> by Eric Elliott</a>.</p>\n<p><a href=\"https://www.amazon.com/Programming-JavaScript-Applications-Architecture-Libraries/dp/1491950293\">Buy <em>Programming JavaScript Applications</em> by Eric Elliott</a>.</p>\n",
      "date_published": "2019-09-08T00:00:00Z"
    },{
      "id": "https://www.falldowngoboone.com/blog/get-started-with-coding/",
      "url": "https://www.falldowngoboone.com/blog/get-started-with-coding/",
      "title": "Where to start your development career",
      "content_html": "<p>Becoming a career developer can be challenging at times. With a ton of material out of the internet, it can be difficult to know where to start. And even if you know where to start, it can be difficult to stay motivated.</p>\n<p>What follows is a brain dump of tips to help you on your journey to coding greatness. I don’t go too deep into anything here, but I may use some of these tips as a jumping off point for future posts.</p>\n<h2 id=\"become-friends-with-your-terminal\" tabindex=\"-1\">Become friends with your terminal<a class=\"c-anchor-link\" href=\"#become-friends-with-your-terminal\" aria-label=\"permalink\" aria-describedby=\"become-friends-with-your-terminal\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>I was intimidated when I first started using my terminal, but now I use it every day. You may be intimidated as well. If you are, know there is hope. The more your use your terminal, the more comfortable you will be with it.</p>\n<p><a href=\"https://lifehacker.com/a-command-line-primer-for-beginners-5633909\">Start with simple tasks</a>, like learning how to navigate your computer or how to read a file. Then, work your way up to more powerful tasks, like creating, updating or deleting files, as well as how to pipe data through multiple tasks. Maybe even do a deep dive into <a href=\"https://devdocs.io/bash/\">bash</a>.</p>\n<h2 id=\"learn-how-to-git\" tabindex=\"-1\">Learn how to git<a class=\"c-anchor-link\" href=\"#learn-how-to-git\" aria-label=\"permalink\" aria-describedby=\"learn-how-to-git\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p><a href=\"https://git-scm.com\">Git</a> is by far the most popular version control system (VCS) available today, and if you want a career in software development, you need to learn how to use it. Preferably within the context of a team.</p>\n<p><a href=\"https://github.com\">Start a Github account</a>. Push and pull code to and from your repo. Create a new branch and open a pull request. And if you’re feeling adventurous, <a href=\"https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain\">learn git’s internals</a>.</p>\n<h2 id=\"take-a-class\" tabindex=\"-1\">Take a class<a class=\"c-anchor-link\" href=\"#take-a-class\" aria-label=\"permalink\" aria-describedby=\"take-a-class\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>There are literally <a href=\"https://github.com/romulomourao/awesome-courses\">hundreds of places to learn development online</a>. My advice is to look for classes that encourage you to build things. It’s also important to get feedback on what you make. Get involved in the class’s community. Show your work. Ask questions. If your class doesn’t provide a channel for feedback, contact me. You can never truly learn where you need improvement without the input of others.</p>\n<p>If you want to supercharge your learning (and you have the time and money), do a <a href=\"https://github.com/theodesp/awesome-coding-camps\">bootcamp</a>. Keep in mind bootcamps are usually designed to expose you to the most current concepts and frameworks in a short amount of time. They are focused on giving you a breadth of knowledge, not necessarily depth. But they also usually help with job placement.</p>\n<h2 id=\"join-a-community\" tabindex=\"-1\">Join a community<a class=\"c-anchor-link\" href=\"#join-a-community\" aria-label=\"permalink\" aria-describedby=\"join-a-community\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>No developer is an island. You need a community of people with like interests that inspire and motivate you on a regular basis. Find some dev <a href=\"https://www.meetup.com\">meetups</a>. Join a <a href=\"https://github.com/filipelinhares/awesome-slack\">dev Slack group</a>. Put yourself out there and make some connections.</p>\n<h2 id=\"keep-at-it\" tabindex=\"-1\">Keep at it<a class=\"c-anchor-link\" href=\"#keep-at-it\" aria-label=\"permalink\" aria-describedby=\"keep-at-it\"><svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#icon-link\" xlink:href=\"#icon-link\"></use></svg></a></h2>\n<p>Learning to code is not easy. It will stretch your brain in ways you never thought possible. But you can do it. I know you can because I did. It took me four years while working a full-time job, but I was able to make the move from designer to developer.</p>\n<p>Honestly, I think the most difficult thing I had to do was figure out what I wanted to do with coding. Being a designer, I naturally gravitated to front-end development, but I wasn’t really sure. It took getting my current job at The Container Store to help me realize I’m passionate about accessibility, scalable CSS, and building UI.</p>\n<p>Build things. Get help when you’re stuck. And don’t be afraid to take on challenges you may not be able to accomplish. When you’re first starting out, you have to figure out what ignites your curiosity.</p>\n<p>If you thought this was helpful, or if you have any questions, let me know on <a href=\"https://twitter.com/therealboone\">Twitter</a> or drop me an email. I am always eager to help.</p>\n",
      "date_published": "2019-06-18T00:00:00Z"
    }
  ]
}
