<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Joe Czubiak</title>
    <description>The latest articles on Forem by Joe Czubiak (@joeczubiak).</description>
    <link>https://forem.com/joeczubiak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F379687%2F4061d9bb-0261-4e3f-a11b-9d333d41d978.jpeg</url>
      <title>Forem: Joe Czubiak</title>
      <link>https://forem.com/joeczubiak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joeczubiak"/>
    <language>en</language>
    <item>
      <title>3 Hotkeys That Will Make You a Faster Developer</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Mon, 07 Jul 2025 09:00:00 +0000</pubDate>
      <link>https://forem.com/joeczubiak/3-hotkeys-that-will-make-you-a-faster-developer-56l8</link>
      <guid>https://forem.com/joeczubiak/3-hotkeys-that-will-make-you-a-faster-developer-56l8</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/97Ivv_L7VUw"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;These are my three favorite hotkeys while coding. They make me faster, more productive, and improve my code quality. On top of that, they reduce my cognitive load and make my code easier to read. I'm using VS Code as my example but you could use them in any IDE you'd like.&lt;/p&gt;

&lt;h2&gt;
  
  
  View and Edit Hotkeys
&lt;/h2&gt;

&lt;p&gt;Before we get into it, here's a quick reminder of how to view and edit your hotkeys in VS Code.&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;Code -&amp;gt; Settings -&amp;gt; Keyboard Shortcuts&lt;/code&gt; or type &lt;code&gt;Cmd + k&lt;/code&gt; then &lt;code&gt;Cmd + S&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Organize Imports
&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;It's like having a clean closet&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shortcut: Shift + Option + O (Mac) | Shift + Alt + O (Windows)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The imports section of your files can easily become a mess with unused imports and the latest import at the bottom of the list — which isn't an organization strategy at all. You might (and you should!) have a lint rule setup to catch unused imports but this command lets you get rid of that error message quickly.&lt;/p&gt;

&lt;p&gt;The "Organize Imports" command (sometimes called "Optimize Imports" in other editors) automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removes unused imports&lt;/li&gt;
&lt;li&gt;Sorts all imports alphabetically&lt;/li&gt;
&lt;li&gt;Eliminates duplicate imports&lt;/li&gt;
&lt;li&gt;Improves overall code readability&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;You might not even realize how messy these imports are but code without an organization strategy applied is simply unorganized and isn't doing your brain any favors.&lt;/p&gt;

&lt;p&gt;Before using this shortcut, your imports might look like this mess:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;CardHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CardTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CardContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CardDescription&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui/card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;//out of order&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui/button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// duplicate&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Alert&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui/alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// unused&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After pressing Shift + Option + O, it becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui/button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CardContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CardDescription&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CardHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CardTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui/card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, organized, and instantly more readable. I make it a habit to run this command anytime I've touched the imports. It's such a simple step that eliminates visual clutter and makes code reviews much smoother.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Sort Lines
&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Because Your Brain Loves Alphabetical Order&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom Shortcut: Ctrl + Option + S (ascending) | Ctrl + Option + D (descending)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of my core coding principles is simply: if you don't have a specific reason to sort something in a particular way, it should just be alphabetical. Our brains are wired for alphabetized things. When dealing with text, which code is, alphabetized lists are nearly always the way to go.&lt;/p&gt;

&lt;p&gt;This one requires a bit of setup since it's not mapped by default, but it's absolutely worth it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting It Up
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open VS Code Shortcuts settings (Cmd + K, Cmd + S)&lt;/li&gt;
&lt;li&gt;Search for "sort"&lt;/li&gt;
&lt;li&gt;Find "Sort Lines Ascending" and "Sort Lines Descending"&lt;/li&gt;
&lt;li&gt;Add your custom keybindings (I use Ctrl + Option + S/D). I find the Control + Option pair is almost never already mapped and I like using it for my custom key mappings.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Let's say you have a list of error messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ERROR_MESSAGES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown_error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An unexpected error occurred. Please try again&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please sign in to access this page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid_credentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The email or password you entered is incorrect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;too_many_requests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too many attempts. Please try again later&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;network_error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network error. Please check your connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email_not_confirmed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please confirm your email address before signing in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of leaving them in random order, select the lines and press Ctrl + Option + S:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ERROR_MESSAGES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email_not_confirmed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please confirm your email address before signing in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid_credentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The email or password you entered is incorrect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;network_error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network error. Please check your connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please sign in to access this page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;too_many_requests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too many attempts. Please try again later&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown_error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An unexpected error occurred. Please try again&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you're scanning through the list, your brain doesn't have to work as hard. Looking for "Unknown error"? It's always going to be at the bottom where "U" belongs. This small change reduces cognitive load and makes code scanning much faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Multiple Cursors
&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Edit Like a Pro&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shortcut: Option + Command + Up/Down (Mac) | Alt + Ctrl + Up/Down (Windows)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This shortcut lets you add cursors above or below your current position, enabling you to edit multiple lines simultaneously. It's a massive time-saver for repetitive edits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Perfect Use Cases
&lt;/h3&gt;

&lt;p&gt;Imagine you have a list of error messages and want to add a period to the end of each:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Database timeout occurred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid user credentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network connection failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Permission denied&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of manually editing each line:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Place your cursor at the end of the first line&lt;/li&gt;
&lt;li&gt;Hold Option + Command and press the down arrow to add cursors to subsequent lines&lt;/li&gt;
&lt;li&gt;Type the period once – it appears on all lines simultaneously&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Database timeout occurred.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File not found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid user credentials.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network connection failed.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Permission denied.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pro Tips for Multiple Cursors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can add as many cursors as you need&lt;/li&gt;
&lt;li&gt;Each cursor operates independently&lt;/li&gt;
&lt;li&gt;Use Escape to return to a single cursor&lt;/li&gt;
&lt;li&gt;This works for any repetitive editing task, not just adding characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PS: You can also add cursors by using Option + Left Click (on your mouse)&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the Shortcuts
&lt;/h2&gt;

&lt;p&gt;While these three shortcuts are my go-to productivity boosters, they represent a larger principle: small, consistent improvements in your development workflow compound into significant gains in productivity and code quality.&lt;/p&gt;

&lt;p&gt;The time you save isn't just about typing faster, it's about reducing the cognitive load of reading and maintaining code. When your imports are organized, your lists are sorted, and your repetitive edits are efficient, you can rest assured that you've been a good steward of the codebase. Your future self and teammates will thank you for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;I reach for these shortcuts daily and feel like they give me a real boost. Give them a try.&lt;/p&gt;

&lt;p&gt;I also encourage you to search for other shortcuts you can use to improve your daily workflow. Let me know what you find.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vscode</category>
      <category>hotkeys</category>
      <category>video</category>
    </item>
    <item>
      <title>A Practical Approach to Renaming a Model in Laravel</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Wed, 06 Mar 2024 00:39:45 +0000</pubDate>
      <link>https://forem.com/joeczubiak/a-practical-approach-to-renaming-a-model-in-laravel-i53</link>
      <guid>https://forem.com/joeczubiak/a-practical-approach-to-renaming-a-model-in-laravel-i53</guid>
      <description>&lt;p&gt;Code is messy, language is messy, and sometimes you want to rename a model in a codebase that a team has sunk years into...for consistency's sake.&lt;/p&gt;

&lt;p&gt;Once a codebase hits a certain size or has multiple active participants, it becomes unrealistic to make sweeping changes like these. These types of sweeping changes inevitably run into problems. An all of nothing approach on this scale can lead to hefty merge conflicts, a massive PR that is hard to review and test, or a feature branch that starts diverging heavily from the main trunk and becomes hard to maintain.&lt;/p&gt;

&lt;p&gt;A more manageable approach to a large change like this, is to break it into smaller pieces that can merge into the main trunk while keeping the project in a working state.&lt;/p&gt;

&lt;p&gt;Doing a quick find and replace isn't enough in this case, as there are some tricky places our model's name might live.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database relationship columns may be referencing the model name, think  &lt;code&gt;{model}_id&lt;/code&gt;, &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;team_id&lt;/code&gt; etc.

&lt;ul&gt;
&lt;li&gt;Quick Tip: If you're using MySQL, you can find all tables referencing the model's name in your database using the following query. &lt;code&gt;SELECT table_name, column_name FROM information_schema.columns WHERE column_name LIKE '%model_name%;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Database indexes may be referencing the same fields.&lt;/li&gt;
&lt;li&gt;Polymorphic relationships in the database may be referencing the model name.&lt;/li&gt;
&lt;li&gt;The model may be serialized in the database or used in our queues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example, we'll be renaming a Team model to Organization in a Laravel codebase.&lt;/p&gt;

&lt;p&gt;To keep the project in a working state, while introducing the new name, we'll take advantage of a PHP built in function,  &lt;a href="https://www.php.net/manual/en/function.class-alias.php"&gt;class_alias&lt;/a&gt;. This will allow both the old model name and the new one to be used in parallel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add an alias
&lt;/h2&gt;

&lt;p&gt;We could use the &lt;code&gt;class_alias&lt;/code&gt; function directly, in somewhere like the boot method of our AppServiceProvider, but Laravel provides a way to add aliases in the app config. So we'll stick to conventions here.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;configs/app.php&lt;/code&gt;, look for &lt;code&gt;aliases&lt;/code&gt; and add an alias from the old model to the new model.&lt;br&gt;
It should look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'aliases'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Facade&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;defaultAliases&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="mf"&gt;...&lt;/span&gt;
    &lt;span class="s1"&gt;'App\Models\Team'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'App\Models\Organization'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where Laravel is loading all of the facades. Under the hood, it is using the PHP function, class_alias.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update the model
&lt;/h2&gt;

&lt;p&gt;Rename the Team model to Organization — both the file and class name.&lt;/p&gt;

&lt;p&gt;We aren't writing any migrations today and to keep the code running, we need to override some of the Laravel auto table name and foreign key features. We want the model's table name to point to the existing table and relationships to use the existing columns in our database.&lt;/p&gt;

&lt;p&gt;Add the table property to the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'teams'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Override the default getForeignKey function in the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getForeignKey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'team_id'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update morph maps
&lt;/h2&gt;

&lt;p&gt;Morph maps are aliases used to reference a class in our database without using the actual class path in the database. This could mean using 'Team' instead of 'App\Models\Team'. You'll most commonly see these used for polymorphic relationships but they could be used for other things as well.&lt;/p&gt;

&lt;p&gt;We need to allow the value that is used in the database to remain the same while mapping to our new model.&lt;/p&gt;

&lt;p&gt;In the morph map, change from: &lt;code&gt;'Team' =&amp;gt; Team::class&lt;/code&gt; to: &lt;code&gt;'Team' =&amp;gt; Organization::class&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Relation&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;enforceMorphMap&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'Team'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Organization&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both &lt;code&gt;(new Team())-&amp;gt;getMorphClass()&lt;/code&gt; and &lt;code&gt;(new Organization())-&amp;gt;getMorphClass()&lt;/code&gt; should now return 'Team'.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the alias
&lt;/h2&gt;

&lt;p&gt;After these steps, our app should be in a working state, only now, we can use both model names interchangeably. References to both Team and Organization will work.&lt;/p&gt;

&lt;p&gt;From here we can chip away at updating our codebase and database to use the new name in bite sized bits. This lets us keep the codebase moving in the direction we want to go, without putting a stop to everything else.&lt;/p&gt;

&lt;p&gt;The downside of course, is that we now have two ways to reference the same model, making things a little confusing in the interim. So don't sleep on the rest of the work.&lt;/p&gt;

&lt;p&gt;Consistency...here we come.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>NFTs beyond art — 3 uses with real utility</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Thu, 11 Mar 2021 12:00:00 +0000</pubDate>
      <link>https://forem.com/joeczubiak/nfts-beyond-art-3-uses-with-real-utility-2omp</link>
      <guid>https://forem.com/joeczubiak/nfts-beyond-art-3-uses-with-real-utility-2omp</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ULaWeoZL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/a86ff9d98bf1098312ba7a562053bbbd/nft-cover.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ULaWeoZL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/a86ff9d98bf1098312ba7a562053bbbd/nft-cover.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NFTs, Non-Fungible Tokens, have broken into the mainstream in the past few weeks.&lt;/p&gt;

&lt;p&gt;Nifties, as some call them, are a way to prove ownership of a digital asset like a photo, illustration, or video using the blockchain. NFTs aren't a currency like BitCoin or Ethereum, they have no intrinsic value, the value of an NFT comes from the value of the actual asset that it represents.&lt;/p&gt;

&lt;p&gt;The NFT markets have been skyrocketing and this excitement and energy is largely centered on NFT art. Digital art is being sold as NFTs. It usually comes in the form of a jpeg, gif, mp4, or other common image and video file formats. NFTs contain metadata and the metadata usually includes a link to the artwork, hosted elsewhere on the web. This means the artwork itself is not on the blockchain but the certificate of ownership, NFT, is on the blockchain or public ledger.&lt;/p&gt;

&lt;p&gt;Because of this, if you want to use one of these pieces of art as your background image on your device, there's nothing in place to stop you. The file is public and anyone can right-click and download it just like any other image on the internet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So then why own NFT art?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nifty art has little utility beyond being able to display it in somewhat obscure virtual worlds. Some say to buy them for bragging rights, because owning things feels good, or to start a collection. Maybe that resonates with you, maybe, like me, it doesn't. I'd say a lot of people are buying NFT art because they don't understand the speculation trap they've fallen into.&lt;/p&gt;

&lt;p&gt;NFTs today, feel a lot like the crypto craze of 2018. The difference is that NFTs have no inherent value, are not a store of value, and there's no way to get your money out besides finding a buyer for your specific token.&lt;/p&gt;

&lt;p&gt;The nifty art market is based on artificial scarcity, hype, and speculation. Artificial scarcity isn't enough to drive lasting value. Almost every article about NFTs mentions Crypto Kitties as an example of the power of artificial scarcity but they overlook the fact that the cats offered utility in that you could breed them and sell the offspring to others, for a profit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond art
&lt;/h2&gt;

&lt;p&gt;While nifty art is getting all the attention, there are very practical use cases for NFTs that will outlast the art craze.&lt;/p&gt;

&lt;p&gt;NFTs have two important traits that make them valuable tools. They are tradable on open markets and they prove ownership. Taking advantage of these traits to provide utility is where the real value of NFTs comes from. NFTs are not art. Art is just one type of asset that an NFT can represent and it's important to remember that.&lt;/p&gt;

&lt;p&gt;These are a few of the real-world scenarios where NFTs could be game-changing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tickets
&lt;/h3&gt;

&lt;p&gt;Tickets are a great use case for NFTs. Tickets to concerts, games, conferences, or other events and shows — both in person and online. In this case, there are already markets set up to sell your tickets to another person but they're fraught with uncertainty and fraud. Oftentimes, all you need is a barcode printed out or on your phone to get into an event. If you bought the ticket second-hand, which has become increasingly the only way due to a proliferation of bots buying tickets as soon as they go on sale, how can you be certain that they didn't sell the same barcode to someone else or several others? First one to arrive gets in and everyone else got scammed. That's not a good system.&lt;/p&gt;

&lt;p&gt;There have been attempts to make physical tickets have holographic or otherwise hard to counterfeit traits but to a one time buyer I wouldn't know how to know if what I'm looking at is real or an elaborate fake.&lt;/p&gt;

&lt;p&gt;This is what provability of ownership solves. With the NFT, you can see that the ticket originated from the official organization in charge of the event and there is no way for someone else to use the ticket. You can be sure that you didn't buy a fraudulent ticket and be sure that it will work to get in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Movies
&lt;/h3&gt;

&lt;p&gt;Movie ownership feels a little different than it used to. We used to own DVDs. They were ours and we could do what we wanted with them, permitting we weren't breaking laws. These days, if you click buy in iTunes, what do you get? You get the privilege to watch the movie from your account, in iTunes, and that's it. There's no transferability. You can't move that movie to Google Play or lend it to a friend because you didn't buy the movie. You bought a privilege to consume it through a service.&lt;/p&gt;

&lt;p&gt;If digital movies instead used the NFT model, you would own a copy of the actual files and you could watch that movie through any service or player that you want. You could give it to a friend for the weekend. When you're tired of it, just like a good old-fashioned garage sale, you could sell it off.&lt;/p&gt;

&lt;p&gt;I don't foresee large movie studios being at the forefront of this innovation, they are currently benefiting from this lopsided system. I would expect smaller studios and independents to be the driving force in this change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game assets
&lt;/h2&gt;

&lt;p&gt;Have you ever bought in-game items? If you have, you've given money to the makers of the game, and in return, you get to use the item with your account in their game and that's it. If instead, you bought an NFT that represents a digital asset in the game, doors start to open. You could exchange your items on a public marketplace. You could show off the items you own on your blog. If you no longer play this game, you can sell off all of your items.&lt;/p&gt;

&lt;p&gt;At first, it feels like all of the power is being given back to the users and the game makers are losing if they adopt NFTs. But, they won't lose if they adapt. NFTs create more reason to buy items and an ability for users to show off items which drives demand for more limited-run items. The switch to an NFT model creates a more thriving market and the ability for the game makers to produce more items to sell.&lt;/p&gt;

&lt;p&gt;There are so many more ways that NFTs can and are being used but just because they can be used, doesn't mean that you should. No article about crypto would be complete without including a mention of the environmental effects of using crypto, which is enormous. With such high environmental costs, NFTs should only be used when it offers real utility and value that is hard to obtain otherwise.&lt;/p&gt;

&lt;p&gt;To understand the environmental costs, I'll send you to this article explaining them. &lt;a href="https://everestpipkin.medium.com/but-the-environmental-issues-with-cryptoart-1128ef72e6a3"&gt;https://everestpipkin.medium.com/but-the-environmental-issues-with-cryptoart-1128ef72e6a3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nft</category>
      <category>crypto</category>
    </item>
    <item>
      <title>Box-Shadows: a journey to understand great shadows</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Thu, 25 Feb 2021 12:30:00 +0000</pubDate>
      <link>https://forem.com/joeczubiak/box-shadows-2h0c</link>
      <guid>https://forem.com/joeczubiak/box-shadows-2h0c</guid>
      <description>&lt;p&gt;I've become mildly obsessed with box-shadows. When they are done well, they're magic. They provide depth, contrast, and clarity to the page. When done poorly, they're distracting. It's apparent to me that most shadows fall short of the magic. It's especially true when I try to apply my own handwritten CSS box-shadow to an element.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's behind a good box-shadow?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I keep finding myself reaching for the shadows defined in Material Design. They are some of the only ones that I think really get it right. Most design frameworks provide their own version of a decent shadow but I find the concept and execution of elevations in Material Design resonates with me. They also have extensive &lt;a href="https://material.io/design/introduction"&gt;design guidelines&lt;/a&gt; that are worth reading.&lt;/p&gt;

&lt;p&gt;I never understood why Material Design shadows are so good and when I make a shadow, it really doesn't look great. They come out too harsh or undefined and unprofessional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the math behind box-shadows?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I see a lot of visual editors like WebFlow or box-shadow generators that give you controls for angle and distance, but angle and distance aren't CSS properties for box-shadow. So then, how do you get the x and y values from angle and distance? &lt;em&gt;Hint: trigonometry is involved.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why don't CSS generators produce good-looking shadows?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The quick answer is that most of them don't support layers and as you're about to learn, having multiple shadow layers is important.&lt;/p&gt;

&lt;p&gt;I had these questions and one night my curiosity got the better of me. At least, I had hoped it would only be one night. It led me back to high school trigonometry and carried me through a weeks long journey into box-shadows. This journey involved building a &lt;a href="https://shadows.joeczubiak.com"&gt;CSS Box-Shadow generator&lt;/a&gt; myself and writing this article that keeps growing in scope.&lt;/p&gt;

&lt;p&gt;Alas, here we are, let's get into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Box-Shadow
&lt;/h2&gt;

&lt;p&gt;Let's take a look at what the box-shadow CSS property is and the values it allows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Syntax:&lt;/strong&gt; &lt;code&gt;box-shadow: x-offset y-offset blur-radius spread color outset/inset&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;box-shadow: 0px 3px 2px 4px #000;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Box-Shadow Values Explained
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;x-offset&lt;/strong&gt; — This is the horizontal offset of the shadow. Higher values will move the shadow to the right like it is traversing the x-axis of a graph. Negative values will move the shadow to the left.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;y-offset&lt;/strong&gt; — This is the vertical offset of the shadow. Higher values will move the shadow further below your object or down the page. Negative values will move the shadow higher vertically up the page. This is the opposite direction you might think of when looking at a graph with the y-axis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;blur-radius&lt;/strong&gt; — Higher values will increase the blurriness and also increase the size of the shadow leading the shadow to become lighter in color. This number can't be less than 0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spread&lt;/strong&gt; — Higher values will increase the size of the shadow without causing any loss of sharpness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;color&lt;/strong&gt; — Specifies the color of the shadow.&lt;/p&gt;

&lt;p&gt;* &lt;strong&gt;outset / inset&lt;/strong&gt; — You can specify the box-shadow to be inset instead of the default outset. This will make the shadow appear inside of the object instead of outside of it. &lt;em&gt;This article is about outset shadows and won't touch on inset shadows&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There's a little bit more to the box-shadow that I did not cover here and I encourage you to look it up elsewhere if you need to know more. This is a good basic understanding for us to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The thing that isn't obvious while working with box-shadows is that you can specify multiple shadows on the same element. Simply, use commas to separate multiple values.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Angle and Distance
&lt;/h2&gt;

&lt;p&gt;It's very common to see the inputs &lt;strong&gt;angle&lt;/strong&gt; and &lt;strong&gt;distance&lt;/strong&gt; in visual editors such as WebFlow and they forgo the x and y offsets. You'll notice though that neither angle nor distance is one of the attributes defined above.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How do angle and distance translate to x-offset and y-offset?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To answer this, we need to dive into some trigonometry.&lt;/p&gt;

&lt;p&gt;The x offset and y offset can be thought of as the x and y coordinates on a graph. Because of this, we can draw a right triangle on the graph from the center point. If you can remember back to your trigonometry days, right triangles are the very basis of the 6 fundamental trig functions.&lt;/p&gt;

&lt;p&gt;I'm going to show you how to calculate the values forwards and reverse. From angle and distance to x and y and then from x and y to angle and distance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Math
&lt;/h2&gt;

&lt;p&gt;Take a look at this graph. We're going to use it as the basis for our calculations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NKu12YZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/d3e7428858d9284f89bcc10020134121/5a190/trig-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NKu12YZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/d3e7428858d9284f89bcc10020134121/5a190/trig-chart.png" alt="Trig Chart" title="Trig Chart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The x and y coordinates are the x-offset and y-offset of the box-shadow properties. When you plot it onto a graph, like the graph shows, it creates a right triangle and the perfect setup for doing a little trigonometry.&lt;/p&gt;

&lt;p&gt;If you understand trig or stare at this graph long enough you'll see how all the pieces fit together. When given the options of angle and distance instead of the x and y, we can see that the angle is angle A in the graph and distance is c or the hypotenuse of the triangle formed.&lt;/p&gt;

&lt;p&gt;These are the two basic functions of trig and the two that we need for our calculations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sin(x) = opposite/hypotenuse = a/c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cos(x) = adjacent/hypotenuse = b/c&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Angle and distance to x and y
&lt;/h3&gt;

&lt;p&gt;Angle and distance to x and y is the calculation that visual editors would use. We let the user pick an angle and distance and then we convert that into an x and y coordinate to use as the x-offset and y-offset in CSS.&lt;/p&gt;

&lt;p&gt;We can use the functions defined above.&lt;/p&gt;

&lt;p&gt;X in our case is the angle, we'll call it angle A as we can see on the graph.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;a&lt;/code&gt; is our y offset.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b&lt;/code&gt; is our x offset.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;c&lt;/code&gt; is our distance.&lt;/p&gt;

&lt;p&gt;In this case, we know the values of angle A and the distance, c. So we need to solve for &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will need to use both the sin and the cos functions. Sine will give us &lt;code&gt;a&lt;/code&gt;, our y, and Cosine will give us &lt;code&gt;b&lt;/code&gt;, our x.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NKu12YZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/d3e7428858d9284f89bcc10020134121/5a190/trig-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NKu12YZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/d3e7428858d9284f89bcc10020134121/5a190/trig-chart.png" alt="Chart" title="Chart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we rearrange the functions they will look like so.&lt;/p&gt;

&lt;p&gt;cos(A) * c = b&lt;/p&gt;

&lt;p&gt;cos(A) * distance = y&lt;/p&gt;

&lt;p&gt;sin(A) * c = b&lt;/p&gt;

&lt;p&gt;sin(A) * distance = x&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using real numbers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;angle = 70&lt;/p&gt;

&lt;p&gt;distance = 9&lt;/p&gt;

&lt;p&gt;sin(70) * 9 = x&lt;/p&gt;

&lt;p&gt;3.08= round down to 3 = x&lt;/p&gt;

&lt;p&gt;cos(70) * 9 = y&lt;/p&gt;

&lt;p&gt;8.45= round to 8 = y&lt;/p&gt;

&lt;p&gt;(x, y) = (3, 8)&lt;/p&gt;

&lt;h3&gt;
  
  
  x and y to angle and distance
&lt;/h3&gt;

&lt;p&gt;This is the calculation to take the x-offset and y-offset from our CSS values and convert it to an angle and distance that we could show to a user in a visual editor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;a&lt;/code&gt; is our y offset.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b&lt;/code&gt; is our x offset.&lt;/p&gt;

&lt;p&gt;In this case, we know the &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; values and we need to solve for angle A and distance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We know that distance is &lt;code&gt;c&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; can be calculated using good old Pathagoreum's theorem. &lt;code&gt;a^2 + b^2 = c^2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;distance = &lt;code&gt;c = sqrt(a^2 + b^2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Angle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To find the angle, we need to do the inverse of the previous calculations, we need to use inverse sine, arcsin, or inverse cosine, arccos. We can use either arcsin or arccosine because we know the values of each of the sides of the triangle.&lt;/p&gt;

&lt;p&gt;We can take the inverse of our function from before and solve for the &lt;code&gt;A&lt;/code&gt; in &lt;code&gt;sin(A)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;A = arcsin(a/c)&lt;/code&gt; or in our terms &lt;code&gt;Angle = arcsin(x/distance)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using real numbers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We'll use the values we calculated from our angle and distance.&lt;/p&gt;

&lt;p&gt;x = 3&lt;/p&gt;

&lt;p&gt;y = 8&lt;/p&gt;

&lt;p&gt;End result should give use &lt;code&gt;angle = 70&lt;/code&gt; and &lt;code&gt;distance = 9&lt;/code&gt; because those were the values that we used above.&lt;/p&gt;

&lt;p&gt;distance = sqrt(8^2 + 3^2) = sqrt(64 + 9) = sqrt(73) = 8.54 = round to 9&lt;/p&gt;

&lt;p&gt;angle = arcsin(8/sqrt(73)) = 69.44 = round up to 70&lt;/p&gt;

&lt;p&gt;That's it, that's how it's calculated. Not too bad if you think about it for a minute.&lt;/p&gt;

&lt;p&gt;These calculations need to be done in radians. If none of the math worked for you, it's likely because your calculator is in degrees mode and you need to flip it to radians.&lt;/p&gt;

&lt;p&gt;I built this quick calculator tool that you can use to test your math or inspect to see how it might be done in javascript.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/joecz/embed/xxEmXKP?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a box-shadow great
&lt;/h2&gt;

&lt;p&gt;Color and opacity, layers, and angle and distance are the three critical parts needed to make a great natural shadow. Get all three right there's no shadow you won't be able to conquer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Color &amp;amp; Opacity
&lt;/h3&gt;

&lt;p&gt;When creating a shadow by hand, the shadow often appears too dark. A couple of ways that you might be tempted to mitigate this is to change the color to something less black and more gray, off-white, etc. The other attribute you might reach for is the blur. Crank up the blur and it will make the shadow appear less dark and sharp due to the lack of concentration the blur provides.&lt;/p&gt;

&lt;p&gt;These strategies might get the job done but it's sloppy and won't give you the best result possible.&lt;/p&gt;

&lt;p&gt;A great shadow mimics our perceived physical reality. So then, a contemplative person might ask — what is a shadow? A shadow is caused by an object blocking light and causing a partial absence of light on the surface behind or below the object.&lt;/p&gt;

&lt;p&gt;With that as our working definition of a shadow, it changes the way we might think about our options for making a shadow less harsh and more natural.&lt;/p&gt;

&lt;p&gt;Let's think through it again.&lt;/p&gt;

&lt;p&gt;Black is the absence of light.&lt;/p&gt;

&lt;p&gt;A shadow is the partial absence of light.&lt;/p&gt;

&lt;p&gt;Therefore, a shadow in our perceived reality is a semi-transparent black.&lt;/p&gt;

&lt;p&gt;In CSS, that would mean setting the opacity of our black to less than one. Setting the color to a semi-transparent black now frees us to use the blur value to shape our shadow and not use it to compensate for something else.&lt;/p&gt;

&lt;p&gt;Semi-transparent black will also allow your shadow to keep looking good on multiple background colors because the transparency will allow the background color to continue to shine through.&lt;/p&gt;

&lt;p&gt;Recommended Opacity Range: 0.04 - 0.25&lt;/p&gt;

&lt;p&gt;eg. &lt;code&gt;rgba(0,0,0, 0.2)&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Layers
&lt;/h2&gt;

&lt;p&gt;It's not overtly obvious that box-shadows supports multiple shadows on one element but this is the key to a great shadow.&lt;/p&gt;

&lt;p&gt;To understand why layering works so well, we need to look at a film technique.&lt;/p&gt;

&lt;h3&gt;
  
  
  3 Point Lighting
&lt;/h3&gt;

&lt;p&gt;There is a well-established technique in film and photography used to light subjects called 3 point lighting. It solves a simple problem. You need to light a subject, often a person, using artificial light sources but in a way that it looks pleasing. Using a single bright light will cast harsh shadows. Three-point lighting is a technique that solves this problem with a relatively low number of lights, three.&lt;/p&gt;

&lt;p&gt;In a traditional setup, you have three types of lights, key light, fill light, and back light. The key light is your brightest source and is often pointed from off-center to the front of your subject. The fill light is a softer light that is often pointed from the other side of the front of your subject to fill in the shadows caused by the key light. The back light is a light that is pointed at your subject from behind and acts to give your subject some definition around the edges.&lt;/p&gt;

&lt;p&gt;It's important to realize that a single artificial light source is often too harsh whether you're talking about photography or CSS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apply this to CSS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To layer shadows, they must be semi-transparent. If they are not, they cannot compound on each other and will rather block one another making the previous layer mostly useless.&lt;/p&gt;

&lt;p&gt;You can think of each layer as being one of the three lights. One of your shadow layers will act as your key light, it will be the heaviest shadow — least transparent. A second layer can be your fill light, a little softer and wider. Lastly, your back light, provides a little extra definition to your edges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Material Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Take a look at how Material Design uses layers to define their shadows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iboX9vXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/aa5d84a49ae4dddf2f92234d5f1e875a/5a190/elevation-3-break-out.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iboX9vXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/aa5d84a49ae4dddf2f92234d5f1e875a/5a190/elevation-3-break-out.png" alt="elevation-3-break-out" title="elevation-3-break-out"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To see the effect of the layering and what impact each has, I've turned the shadows into red, green, and blue. Opacity 20 layer is red. Opacity 14 layer is green. Opacity 12 layer is blue.&lt;/p&gt;

&lt;p&gt;Notice how the colors interact with each other and create colors, like purple, that weren't used. This also highlights the effect that each shadow has on the box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fmt2YLC0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/be50b8554c6adcd2e87fb5b6b1b3db39/3d4b6/material-z3-in-rbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fmt2YLC0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://joeczubiak.com/static/be50b8554c6adcd2e87fb5b6b1b3db39/3d4b6/material-z3-in-rbg.png" alt="material-z3-in-rbg" title="material-z3-in-rbg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Elevation
&lt;/h2&gt;

&lt;p&gt;The way a shadow is cast can signify how high above the surface the object is floating. Using different 'elevations' of objects can be an important indicator in your design.&lt;/p&gt;

&lt;p&gt;The further an object is from a surface, the larger the shadow it will cast. In CSS this would translate to a larger blur-radius and spread.&lt;/p&gt;

&lt;p&gt;The higher an object is, the further down the screen you'll want the shadow to appear.&lt;/p&gt;

&lt;p&gt;Using a combo of blur-radius, spread, and y-offset will allow you to portray height.&lt;/p&gt;

&lt;h2&gt;
  
  
  Into the shadows
&lt;/h2&gt;

&lt;p&gt;With that, my journey comes to an end but hopefully, this is just the beginning of your journey. To experiment with box-shadows, I encourage you to try out the &lt;a href="https://shadows.joeczubiak.com"&gt;box-shadow generator tool&lt;/a&gt; that I built. Good luck. Hope to see you in the shadows.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>I built a box-shadow generator</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Wed, 10 Feb 2021 16:55:52 +0000</pubDate>
      <link>https://forem.com/joeczubiak/i-built-a-box-shadow-generator-1jcf</link>
      <guid>https://forem.com/joeczubiak/i-built-a-box-shadow-generator-1jcf</guid>
      <description>&lt;p&gt;&lt;a href="https://shadows.joeczubiak.com"&gt;https://shadows.joeczubiak.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built an open-source CSS box-shadow generator this week.&lt;/p&gt;

&lt;p&gt;I was trying out WebFlow the other day and I noticed that like a lot of visual editors, it lets you specify an angle and distance on your box-shadows but both angle and distance aren't CSS attributes on box-shadow. So I decided to explore how angle and distance are converted to an x and y offset.&lt;/p&gt;

&lt;p&gt;I started to write an article detailing the math behind it, turns out it's basic trigonometry and if I was still in 9th grade it would have been obvious, but before you know it and before the article was done I built and released my own CSS generator. &lt;/p&gt;

&lt;p&gt;It taught me a lot about shadows and was a good overall exercise that I hope will now live on to help others.&lt;/p&gt;

&lt;p&gt;I found that a good shadow is built with layers and opacity and mimic real-world behavior. The ability to specify multiple layers in a box-shadow isn't intuitive and most box-shadow generators online don't allow multiple shadows to be specified. They also don't typically give you a great preview. This is where I tried to make mine different. I made it easy to add multiple shadows, the page and preview cards are customizable, and there are presets from popular frameworks. &lt;/p&gt;

&lt;p&gt;Take a look and let me know what you think. I built it this week so it's not totally polished and I'm open to suggestions.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>css</category>
      <category>webdev</category>
      <category>news</category>
    </item>
    <item>
      <title>My secret to putting my email on my website without getting spammed</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Wed, 27 Jan 2021 16:00:00 +0000</pubDate>
      <link>https://forem.com/joeczubiak/my-secret-to-putting-my-email-on-my-website-without-getting-spammed-36jc</link>
      <guid>https://forem.com/joeczubiak/my-secret-to-putting-my-email-on-my-website-without-getting-spammed-36jc</guid>
      <description>&lt;p&gt;I got an email from Ugohow the other day. Ugohar also sent me one. The Ugos send me a lot of emails, they write to me in Russian with links to buy prescription drugs.&lt;/p&gt;

&lt;p&gt;Thanks, Ugos.&lt;/p&gt;

&lt;p&gt;The Ugos are just a small subset of the spammers I regularly receive contact from. Most of them try to sell me web services like SEO, development, or marketing services. The Ugos and their friends are abusing my contact forms and public email addresses that I have on my websites. I put up with Ugos and friends because sometimes a real human needs to get in contact and I want them to be able to do so in the easiest way possible. Sometimes that's the whole point of a website, to get leads by encouraging visitors to contact you.&lt;/p&gt;

&lt;p&gt;Somedays the spam feels overwhelming, while I looked back at my emails for this article I found that some days I was getting over 10 emails a day that were all landing in my inbox and not in the spam folder. That's from one website. I built out my personal blog website recently and I was faced with the decision of what to include on my contact page. Contact form or email address or both. My domain name is my name, literally, and I want to at least try to keep the spam down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contact forms are the worst
&lt;/h2&gt;

&lt;p&gt;It might feel like having a contact form on your website is the best experience for everyone, but contact forms are kind of the worst. I would prefer to pop an email address into my Gmail and be done with it instead of dealing with contact forms with annoying requirements and dropdowns. Sending from my email app also gives me a record of what I said and when I said it.&lt;/p&gt;

&lt;p&gt;On the other end, it's pretty easy to f›‹¢k up the server-side of a contact form. Not speaking from experience or anything. Configure it wrong, and it ends up in spam or doesn't get sent at all. Whoops, forgot to include their email address. Thanks for contacting the black void, see you — never. There are a million ways it goes wrong. A more foolproof way is to just copy and paste an email address into your Gmail.&lt;/p&gt;

&lt;p&gt;Contact forms are ripe targets for spammers. Low hanging fruit, something they've nearly perfected. You don't want to live through the consequences of not using some sort of bot blocker like reCaptcha on your contact form.&lt;/p&gt;

&lt;p&gt;Even though the case against contact forms is strong, some people like the things, and we aim to please on the internet. So, the polite thing to do is to include both a contact form and an actual email address. It feels hard to publicly display your email address, especially when it's a personal address and not some generic support address. How many times have you seen joe [at] gmAil dot c0m or some variation of strange obscurities? We have good reason to be frightened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The internet is mostly bots.
&lt;/h2&gt;

&lt;p&gt;So much internet traffic comes from bots that you'd be forgiven if you thought your site was a lot more popular than it is after looking at your server logs. Some are good bots like Google's search engine crawler. You want that one to ping your website and put the latest content onto Google's search results. Others are less clear about their motive. Fighting traffic from bots is mostly a lost cause, but ignoring them altogether isn't a great plan either.&lt;/p&gt;

&lt;p&gt;The internet is built on content being crawled and information being disseminated and tangled into the web. Keeping personal information out of that process can be difficult, but not impossible. We need to understand how web scraping works in order to work around it.&lt;/p&gt;

&lt;p&gt;Traditional web scraping works like this. A script runs and downloads the contents of a webpage in its raw code form. To see what this looks like, you can right-click on the webpage you're on and click "view source". That's what a web scraper usually takes in. It can then parse out the bits that it wants.&lt;/p&gt;

&lt;p&gt;Traditional scrapers don't load or run any javascript, they only load the server-side generated code. This is one of the reasons that SEO can be so tough for javascript based websites. If your site renders in the browser as opposed to the server, there's a good chance the content won't be available when the crawler hits the site. This is a big part of why server-side rendering (SSR) is so popular for javascript based websites. Node-based web crawlers are increasing in popularity because they can load and render javascript but they can be slower are still in the minority.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trick
&lt;/h2&gt;

&lt;p&gt;Finally, we arrive at my secret to putting my email address on my website without being spammed. Since most of the crawlers are just grabbing the server-side rendered page, we need to take our email out of the server-rendered DOM and add it back in using javascript after the page loads. This way, users visiting your website will be able to see your email, after a short delay, but when your webpage is scraped, it won't be readable by the bots since it wasn't in the DOM when your page was crawled.&lt;/p&gt;

&lt;p&gt;To implement this, you could use javascript's timeout function to set a delay and call a function that adds the email to the DOM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setTimeout(() =&amp;gt; {
  addEmailToDOM(`your-public@email.com`)
}, 1000) // 1000ms or 1 second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of many ways you could go about doing this. To get it working on your website would depend on your setup. This isn't a foolproof method — almost nothing is. It's a simple trick that might just help you avoid some spam.&lt;/p&gt;

&lt;p&gt;Let me know what you think of this method. Do you think it works?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>email</category>
      <category>spam</category>
    </item>
    <item>
      <title>Laravel + React</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Fri, 16 Oct 2020 19:43:26 +0000</pubDate>
      <link>https://forem.com/joeczubiak/laravel-react-3ic1</link>
      <guid>https://forem.com/joeczubiak/laravel-react-3ic1</guid>
      <description>&lt;p&gt;This tutorial will show you how to use React with Laravel in a way that lets you sprinkle React into a legacy Laravel codebase and blade templates. We will not be creating an SPA or using Create React App.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can view and download the full sample project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jcz530/laravel-plus-react" rel="noopener noreferrer"&gt;https://github.com/jcz530/laravel-plus-react&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  After going through this guide...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We'll be able to add React components into blade files.&lt;/li&gt;
&lt;li&gt;We'll have reusable components that can be combined to make complex components.&lt;/li&gt;
&lt;li&gt;We'll use webpack (Laravel Mix) to build our files.&lt;/li&gt;
&lt;li&gt;We &lt;strong&gt;will not&lt;/strong&gt; have an SPA.&lt;/li&gt;
&lt;li&gt;React &lt;strong&gt;will not&lt;/strong&gt; be served with SSR (Server Side Rendering).&lt;/li&gt;
&lt;li&gt;We &lt;strong&gt;will not&lt;/strong&gt; be able to use the components as inline components like is popular with Vue.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;I was inspired to write this guide because recently, I added React into a legacy project of mine, and I didn't want to rewrite the whole project to turn it into a React SPA. Instead, I wanted to reap the benefits of writing new React components that I could start sprinkling into my project right away.&lt;/p&gt;

&lt;p&gt;There are a lot of ways to get React to load and render components, and this is simply the method I choose when working on my project. I'll walk you through how and why I chose this setup.&lt;/p&gt;

&lt;p&gt;First thing's first, navigate to your existing or new Laravel project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Dependencies
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npm i react react-dom&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Folder Structure
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;/resources/js/&lt;/code&gt; folder, we'll add a new folder where all of our React files will live. We want to keep these files all together and not mixed in with other JS files. This will keep the project organized, make some of the webpack setup easier, and allow for the use of other technologies.&lt;/p&gt;

&lt;p&gt;In my case, I created a source folder for all of my React files at &lt;code&gt;/resources/js/src/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I have the following folders in the &lt;code&gt;src&lt;/code&gt; folder.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/src/components&lt;/li&gt;
&lt;li&gt;/src/hooks&lt;/li&gt;
&lt;li&gt;/src/layouts&lt;/li&gt;
&lt;li&gt;/src/pages
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your exact folders may vary depending on your needs and organizational style, but this could be a good place to start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Laravel Mix - Webpack setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Aliases
&lt;/h3&gt;

&lt;p&gt;This step is optional, but I think it makes the project a lot easier and cleaner to work with. Defining aliases in the webpack configs will allow you to refer to your files without needing to know where in the file path you are.&lt;/p&gt;

&lt;p&gt;For example, if you want to refer to your theme file from a component deep in the folder structure, without aliases, you might write&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import theme from '../../../themes/theme.js'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With aliases, you would simply write&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import theme from 'themes/theme.js'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To use aliases, you'll need to add them to your mix file &lt;code&gt;webpack.mix.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;webpackConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//adding react and react-dom may not be necessary for you but it did fix some issues in my setup.&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/src/components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/src/pages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;themes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/src/themes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;layouts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/src/layouts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/src/hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
webpack.mix.js





&lt;h3&gt;
  
  
  Bundle and Extract React
&lt;/h3&gt;

&lt;p&gt;After you've added your aliases, you'll need to tell webpack to bundle your files and extract libraries. In the same  &lt;code&gt;webpack.mix.js&lt;/code&gt; file, add the following line. Notice that we're using &lt;code&gt;mix.react&lt;/code&gt; and we are using &lt;code&gt;app.js&lt;/code&gt;. If your app.js file already has legacy code, you could create a new app file for the React components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
webpack.mix.js





&lt;h2&gt;
  
  
  Rendering the components
&lt;/h2&gt;

&lt;p&gt;This is where things get tricky.&lt;/p&gt;

&lt;p&gt;Even though we aren't building an SPA, we still want to be able to build complex components that reuse multiple components. We're going to be mixing React components into blade files, and it would be great if we could retain some of the JS feel for the components so that we know we're referring to a React component, and it's not just a random div with an id.&lt;/p&gt;

&lt;p&gt;Instead of referring to components as &lt;code&gt;&amp;lt;div id="MyComponent" /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We are instead going to use &lt;code&gt;&amp;lt;MyComponent /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This isn't valid html, so if you want to use the id method, all you'll have to do is uncomment one of the lines in the ReactRenderer.js file coming up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a simple component
&lt;/h3&gt;

&lt;p&gt;We need a simple component to test with, and this is about as simple as they get.&lt;/p&gt;

&lt;p&gt;Create a new file with the following code in &lt;code&gt;src/components/MySimpleComponent.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MySimpleComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;was&lt;/span&gt; &lt;span class="nx"&gt;loaded&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
components/MySimpleComponent.js





&lt;h3&gt;
  
  
  Set up app.js
&lt;/h3&gt;

&lt;p&gt;Next, we need to set up the app.js file. These are the lines that you'll need to add to the app.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactRenderer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/ReactRenderer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MySimpleComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components/MySimpleComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MySimpleComponent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MySimpleComponent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReactRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;renderAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
app.js





&lt;p&gt;&lt;strong&gt;A little explanation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our app.js file we will import any components that we want to use within the blade files and add them to an array. We'll use the 'name' element to find all the references to the component in the blade files, and we'll use the 'component' element to render it.&lt;/p&gt;

&lt;p&gt;Next we need to add the &lt;code&gt;ReactRenderer.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReactRenderer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;renderAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;componentIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;componentIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;componentIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="c1"&gt;// Use this to render React components in divs using the id. Ex, &amp;lt;div id="MySimpleComponent"&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// let container = document.getElementById(this.components[componentIndex].name);&lt;/span&gt;

      &lt;span class="c1"&gt;// Use this to render React components using the name as the tag. Ex, &amp;lt;MySimpleComponent&amp;gt;&amp;lt;/MySimpleComponent&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;componentIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containers&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPropsFromAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
          &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;componentIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nx"&gt;props&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;

          &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Turns the dom element's attributes into an object to use as props.&lt;/span&gt;
  &lt;span class="nf"&gt;getPropsFromAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attributeIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attributeIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attributeIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;attributeIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasJsonStructure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;hasJsonStructure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[object Object]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[object Array]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
ReactRenderer.js





&lt;p&gt;You can read through the code to more fully understand what is happening. At its core, it's just finding all DOM elements that match your components and rendering them with any props included as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put it to work
&lt;/h2&gt;

&lt;p&gt;Now that we have everything in place, we can start to build more components and add them to blade files.&lt;/p&gt;

&lt;p&gt;Here are some examples of adding it to blade files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="mf"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MySimpleComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MySimpleComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;guest&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MySecondComponent&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"This is using blade's &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;{'@'}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;guest helper to show to 'Guests' only"&lt;/span&gt;
&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;endguest&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nc"&gt;Remember&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="s2"&gt;"json_encode"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MySecondComponent&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"This is showing to authed users"&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ json_encode(auth()-&amp;gt;user()) }}"&lt;/span&gt;
&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;endauth&lt;/span&gt;
&lt;span class="mf"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
app.blade.php





&lt;p&gt;In the source code for this tutorial, I've also included a second component that accepts a &lt;code&gt;title&lt;/code&gt; prop. This code is a snippet from the &lt;code&gt;app.blade.php&lt;/code&gt; file in the source code.&lt;/p&gt;

&lt;p&gt;If you download and run the sample project, you will get something that looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqfizp5tve23ow18oqjjp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqfizp5tve23ow18oqjjp.png" alt="Laravel + React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I encourage you to download the repo, explore, and make modifications to test it out. &lt;a href="https://github.com/jcz530/laravel-plus-react" rel="noopener noreferrer"&gt;https://github.com/jcz530/laravel-plus-react&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>laravel</category>
      <category>react</category>
    </item>
    <item>
      <title>Bridging CMS content and react components via shortcodes</title>
      <dc:creator>Joe Czubiak</dc:creator>
      <pubDate>Tue, 04 Aug 2020 22:24:23 +0000</pubDate>
      <link>https://forem.com/joeczubiak/bridging-cms-content-and-react-components-via-shortcodes-4481</link>
      <guid>https://forem.com/joeczubiak/bridging-cms-content-and-react-components-via-shortcodes-4481</guid>
      <description>&lt;p&gt;Recently I've taken up blogging as it were. I'm more of a developer than a writer but when it comes to the blog I thought it would be nice to use a proper CMS instead of coding in paragraph tags or writing in markdown. I don't need to make writing any harder than it is.&lt;/p&gt;

&lt;p&gt;The problem that comes up as a developer writing with a CMS is that there's no bridge that allows you to mix a little code in with your content. If you're writing — you're writing. If you're coding — you're coding. There's no mingling going on. I want them to get to know each other.&lt;/p&gt;

&lt;p&gt;Let's say I want to include an interactive or live map or chart that I built like I did in my &lt;a href="https://joeczubiak.com/joes-apis"&gt;APIs post&lt;/a&gt;. There's really not a great way to do that, especially in the middle of the content. We could write something custom into our post template to add a component at the end of a certain post but that's never a good idea.&lt;/p&gt;

&lt;p&gt;This is where Shortcodes come in. Shortcodes is a concept popularized by &lt;a href="https://wordpress.com/support/shortcodes/"&gt;WordPress&lt;/a&gt; in which you can insert a short snippet into square brackets, for example [contact-form]. Where you place the shortcode in your content is where the actual component will load. &lt;/p&gt;

&lt;p&gt;I thought it would be nice to create my own implementation of shortcodes for my blog so I can include my custom react components into my post by adding a simple shortcode. This creates the bridge between CMS and code that I was missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diving in
&lt;/h2&gt;

&lt;p&gt;We are using React in this example. The CMS that you use does not matter. I'm borrowing the concept from WordPress but went a different way in implementation; we're not going to use square brackets but instead a new html tag &lt;code&gt;&amp;lt;sc&amp;gt;&lt;/code&gt; for shortcode. This is not an existing tag but rather a tag we are creating so that we can find our shortcodes when we render our page.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CMS
&lt;/h2&gt;

&lt;p&gt;At the end of this process we will be able to insert an html snippet into our post in the CMS and use our shortcode tag like this.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;sc comp="ContactForm"&amp;gt;Contact Form&amp;lt;/sc&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We define an attribute called 'comp' (component), this will specify which component we use to render the shortcode. We also should include some text in-between the tags to remind us what is loading here because when you are looking at the text in your CMS, the shortcode will look blank and you won't remember that you have a shortcode there unless you put in this descriptive text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering the content
&lt;/h2&gt;

&lt;p&gt;The trick to making this work is running an html parser instead of simply loading in the html. You might be used to loading your content with something like &lt;code&gt;&amp;lt;div dangerouslySetInnerHTML={{ __html: post.html }} /&amp;gt;&lt;/code&gt;. In our version we are going to replace that with our own implementation so it looks like &lt;code&gt;&amp;lt;HtmlParser html={post.html} /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to build our HtmlParser. Our component will rely on the &lt;a href="https://www.npmjs.com/package/html-react-parser"&gt;html-react-parser&lt;/a&gt; library. You will need to include that with your package manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// import your components the shortcodes reference.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ContactForm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;components/ContactForm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;parse&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html-react-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HtmlParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Replace shortcodes with their react component counterpart&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If we find the '&amp;lt;sc&amp;gt;' tag then we need to replace it.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`sc`&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comp&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`ContactForm`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ContactForm&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comp&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`AnotherComponent`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AnotherComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;domNode&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;HtmlParser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we parse through the html and find the  tags, we then use the comp attribute to check if it's an existing component and then explicitly load the component. For any new shortcodes, you'll have to add it to the HtmlParser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now they're mingling
&lt;/h2&gt;

&lt;p&gt;Now the code and content are talking to each other. This opens a lot of doors for making creative posts.&lt;/p&gt;

&lt;p&gt;There are so many ways we could have gone about creating our shortcode system. This is just a starting point to help you think about bridging the CMS code gap. Further improvements could include allowing props to be passed to the components.&lt;/p&gt;

</description>
      <category>react</category>
      <category>cms</category>
      <category>shortcode</category>
      <category>blogging</category>
    </item>
  </channel>
</rss>
