<?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>DEV Community: Andrew Boyd</title>
    <description>The latest articles on DEV Community by Andrew Boyd (@andrewboyd).</description>
    <link>https://dev.to/andrewboyd</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%2F389593%2F7b6d0622-0280-4694-9644-8c3ff2d71697.jpeg</url>
      <title>DEV Community: Andrew Boyd</title>
      <link>https://dev.to/andrewboyd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andrewboyd"/>
    <language>en</language>
    <item>
      <title>Using Zod with FormKit</title>
      <dc:creator>Andrew Boyd</dc:creator>
      <pubDate>Thu, 18 May 2023 19:11:00 +0000</pubDate>
      <link>https://dev.to/andrewboyd/using-zod-with-formkit-2m8c</link>
      <guid>https://dev.to/andrewboyd/using-zod-with-formkit-2m8c</guid>
      <description>&lt;p&gt;Starting with Beta 17 — &lt;a href="https://formkit.com" rel="noopener noreferrer"&gt;FormKit&lt;/a&gt; ships with a new &lt;a href="https://formkit.com/plugins/zod" rel="noopener noreferrer"&gt;Zod plugin&lt;/a&gt; that you can use to validate your forms.&lt;/p&gt;

&lt;p&gt;By leveraging &lt;a href="https://zod.dev" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; for your form validation you are able to use the same type-definitions to validate your application’s data on the front-end and the back-end — saving you time and reducing the opportunities for malformed data to find its way into your database.&lt;/p&gt;

&lt;p&gt;The FormKit Zod plugin not only validates your data before it is submitted — it provides &lt;strong&gt;real-time validation feedback on a per-input level&lt;/strong&gt;! No more giant block of Zod errors at the top or bottom of your form on submit. 🚀&lt;/p&gt;

&lt;p&gt;It's easy to set up and use, so let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To start, we will need to install both the &lt;code&gt;@formkit/zod&lt;/code&gt; and &lt;code&gt;zod&lt;/code&gt; packages into our FormKit project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# npm, yarn, pnpm — whatever you prefer&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @fomkit/zod zod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Don't have FormKit set up in your project yet? &lt;a href="https://formkit.com/getting-started/installation" rel="noopener noreferrer"&gt;Read the getting started docs here&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Now in our project we will be able to import &lt;code&gt;createZodPlugin&lt;/code&gt; from &lt;code&gt;@formkit/zod&lt;/code&gt; and provide it with a schema we can define using the &lt;code&gt;z&lt;/code&gt; import from &lt;code&gt;zod&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;createZodPlugin&lt;/code&gt; accepts two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zodSchema&lt;/code&gt;: The Zod schema that we define in our app (or more likely import from a shared location).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;submitCallback&lt;/code&gt;: A function that receives valid &lt;code&gt;formData&lt;/code&gt; and allows us to do something with it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;createZodPlugin&lt;/code&gt; returns a tuple with two values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zodPlugin&lt;/code&gt;: The plugin that should be added to your target FormKit form.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;submitHandler&lt;/code&gt;: The submit handler function to be attached to your target form. It is responsible for validating your form data against the provided Zod schema and calling your &lt;code&gt;submitCallback&lt;/code&gt; when the data is valid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The structure for setup in a Vue file looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;createZodPlugin&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;@formkit/zod&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;z&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;zod&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;zodSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// Zod schema here...&lt;/span&gt;
  &lt;span class="c1"&gt;// in a real app you probably import this &lt;/span&gt;
  &lt;span class="c1"&gt;// from somewhere else.&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;zodPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;submitHandler&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createZodPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;zodSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&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;// a submit function here where we &lt;/span&gt;
    &lt;span class="c1"&gt;// do something with our valid data.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;
    &lt;span class="na"&gt;:plugins=&lt;/span&gt;&lt;span class="s"&gt;"[zodPlugin]"&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;submit=&lt;/span&gt;&lt;span class="s"&gt;"submitHandler"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="c"&gt;&amp;lt;!-- Your matching form structure here --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A real example
&lt;/h2&gt;

&lt;p&gt;Here is a full example — first the code block and then a live demo of the output — using the above setup code. &lt;/p&gt;

&lt;p&gt;Note that there are no &lt;code&gt;validation&lt;/code&gt; props on our &lt;code&gt;FormKit&lt;/code&gt; components — all validation is being derived from the provided Zod schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;createZodPlugin&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;@formkit/zod&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;z&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;zod&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;zodSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;personalInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;zodPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;submitHandler&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createZodPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;zodSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&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;// fake async submit handler, but this is where you&lt;/span&gt;
    &lt;span class="c1"&gt;// do something with your valid data.&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&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;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Form was submitted!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&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="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Validation from Zod schema&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt; 
    &lt;span class="na"&gt;:plugins=&lt;/span&gt;&lt;span class="s"&gt;"[zodPlugin]"&lt;/span&gt; 
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;submit=&lt;/span&gt;&lt;span class="s"&gt;"submitHandler"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"group"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"personalInfo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"firstName"&lt;/span&gt;
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"First Name"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; 
        &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"lastName"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Last Name"&lt;/span&gt; 
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
     &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; 
     &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; 
     &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Your email"&lt;/span&gt; 
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;
      &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"features"&lt;/span&gt;
      &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Zod features"&lt;/span&gt;
      &lt;span class="na"&gt;:options=&lt;/span&gt;&lt;span class="s"&gt;"['Validation', 'Type-Safety', 'Reusability']"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the same example in an interactive demo with &lt;code&gt;validationVisibility&lt;/code&gt; set to &lt;code&gt;live&lt;/code&gt; for demonstration purposes. If your browser does not support the embed, click the &lt;code&gt;Fork on StackBlitz&lt;/code&gt; button to open in a new tab.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/vue3-script-setup-with-vite-ptlbhx?ctl=1&amp;amp;embed=1&amp;amp;file=src/App.vue&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's a brief overview of the new Zod plugin that ships with FormKit. If you'd like to learn more you can &lt;a href="https://formkit.com/plugins/zod" rel="noopener noreferrer"&gt;read the official documentation on FormKit.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;More of a visual learner? VueSchool.io has released a free 8-minute video that covers the FormKit Zod plugin. You can &lt;a href="https://vueschool.io/lessons/formkit-and-zod" rel="noopener noreferrer"&gt;watch it for free here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now kneel before Zod!&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/http%3A%2F%2Fwww.reactiongifs.com%2Fwp-content%2Fuploads%2F2013%2F07%2Fzod.gif" 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/http%3A%2F%2Fwww.reactiongifs.com%2Fwp-content%2Fuploads%2F2013%2F07%2Fzod.gif" alt="Zod from the Superman II movie"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zod</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Effortless Floating Labels for Inputs in Vue.js</title>
      <dc:creator>Andrew Boyd</dc:creator>
      <pubDate>Wed, 08 Feb 2023 19:13:52 +0000</pubDate>
      <link>https://dev.to/andrewboyd/effortless-floating-labels-for-inputs-in-vuejs-3m31</link>
      <guid>https://dev.to/andrewboyd/effortless-floating-labels-for-inputs-in-vuejs-3m31</guid>
      <description>&lt;p&gt;Have you ever seen those fancy floating label treatments on form inputs? They look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3l69roswajsxn857hi1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3l69roswajsxn857hi1.gif" alt="FormKit floating label" width="481" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wouldn't it be great if you could do that in your Vue projects in just a few lines of code? &lt;/p&gt;

&lt;p&gt;Well — you can!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up floating labels in your Vue Project
&lt;/h2&gt;

&lt;p&gt;In order to quickly set up floating labels in our Vue project we'll be reaching for &lt;code&gt;@formkit/vue&lt;/code&gt;, it's default theme from &lt;code&gt;@formkit/themes&lt;/code&gt; and its floating label plugin from the &lt;code&gt;@formkit/addons&lt;/code&gt; package — it's all free and open-source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @formkit/vue @formkit/themes @formkit/addons
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in our Vue project, we'll install the supporting FormKit package and its floating label plugin.&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="c1"&gt;// main.js&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;createApp&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;vue&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;App&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;App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// FormKit imports&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;plugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;formKitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&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;@formkit/vue&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;createFloatingLabelsPlugin&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;@formkit/addons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/themes/genesis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/addons/css/floatingLabels&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formKitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;createFloatingLabelsPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// set to true to have floating labels be the default.&lt;/span&gt;
      &lt;span class="c1"&gt;// otherwise, use the `:floating-label` prop&lt;/span&gt;
      &lt;span class="na"&gt;useAsDefault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&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;



&lt;p&gt;That's it! Now when we create a &lt;code&gt;&amp;lt;FormKit /&amp;gt;&lt;/code&gt; input in the text family (things like &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;textarea&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, etc) we will automatically have floating labels!&lt;/p&gt;

&lt;p&gt;You can see it action and try it for yourself on the interactive FormKit playground: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://formkit.link/9d2b7db47b0ed4eb1f6f49e545779101" rel="noopener noreferrer"&gt;https://formkit.link/9d2b7db47b0ed4eb1f6f49e545779101&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldpsgzyrufz308iqsbsb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldpsgzyrufz308iqsbsb.gif" alt="FormKit floating labels across input types" width="807" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Learn more about FormKit
&lt;/h1&gt;

&lt;p&gt;FormKit is a free and open-source form framework for Vue.js.&lt;/p&gt;

&lt;p&gt;Want to learn about FormKit and how it can help with form structure, validation, accessibility, and more?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check out the floating label plugin docs at &lt;a href="https://formkit.com/plugins/floating-labels" rel="noopener noreferrer"&gt;https://formkit.com/plugins/floating-labels&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Join the FormKit Discord community for support, chat with the maintainers, and meet others using FormKit in their own projects: &lt;a href="https://discord.gg/2q3UZkUQbR" rel="noopener noreferrer"&gt;https://discord.gg/2q3UZkUQbR&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>vue</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build a Multi-Step Form in Vue in 5 minutes.</title>
      <dc:creator>Andrew Boyd</dc:creator>
      <pubDate>Mon, 06 Feb 2023 19:15:00 +0000</pubDate>
      <link>https://dev.to/andrewboyd/build-a-multi-step-form-in-vue-in-5-minutes-41cj</link>
      <guid>https://dev.to/andrewboyd/build-a-multi-step-form-in-vue-in-5-minutes-41cj</guid>
      <description>&lt;p&gt;Few interactions on the web cause as much displeasure for a user as being confronted with a large, intimidating form. Multi-step forms can alleviate this pain by breaking a large form into smaller, approachable steps — but they can also be quite complicated to build.&lt;/p&gt;

&lt;p&gt;In this guide, we'll walk through building a multi-step form with FormKit (a free and open-source form building framework) and see how we can provide an elevated user experience with minimal code. We'll be done in approximately 5 minutes. Let's get started!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Not familiar with FormKit? It's a free and open-source framework for building forms in Vue and you can learn more about it &lt;a href="https://dev.to/justinschroeder/introducing-formkit-a-vue-3-form-building-framework-53ji"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To get started we need to install FormKit, its supporting default theme, and the FormKit Multi-Step plugin into our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @formkit/vue @formkit/addons @formkit/themes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we add FormKit to our Vue app, add the Multi-Step Plugin to our FormKit config, and ensure that we're including the necessary styles:&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="c1"&gt;// main.js&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;createApp&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;vue&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;App&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;App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// FormKit imports&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;plugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;formKitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&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;@formkit/vue&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;createMultiStepPlugin&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;@formkit/addons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/themes/genesis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@formkit/addons/css/multistep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formKitPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;createMultiStepPlugin&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="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&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;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Out-of-the-box, FormKit ships with every native HTML input available to you. Things like &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;checkbox&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;createMultiStepPlugin&lt;/code&gt; registers two brand-new input types for you to use with FormKit — in exactly the same way you use any other input type.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;multi-step&lt;/code&gt;: The wrapping group for the entire multi-step input.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;step&lt;/code&gt;: The wrapping group for a given step within your multi-step input.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these inputs together is as simple as wrapping any markup you want to have present within a step in a multi-step form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"multi-step"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"step"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"stepOne"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- content for stepOne goes here! --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So — let's build a quick form for users who want to submit a talk to our upcoming fake conference, VueUniverse.&lt;/p&gt;

&lt;p&gt;We'll want to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collect some contact information for the user.&lt;/li&gt;
&lt;li&gt;Get a brief overview of the talk the user wants to give.&lt;/li&gt;
&lt;li&gt;Ask the user how they heard about VueUniverse. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those sound like good groupings for our steps — so let's get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"multi-step"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"step"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"contactInformation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- collect name, email, and company info --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Your Name"&lt;/span&gt; 
        &lt;span class="na"&gt;validation=&lt;/span&gt;&lt;span class="s"&gt;"required"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Your Email"&lt;/span&gt; 
        &lt;span class="na"&gt;validation=&lt;/span&gt;&lt;span class="s"&gt;"required|email"&lt;/span&gt; 
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Your Company (optional)"&lt;/span&gt;
        &lt;span class="na"&gt;help=&lt;/span&gt;&lt;span class="s"&gt;"Are speaking on behalf of an organization?"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"step"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"talkDetails"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Get talk title, brief, and track --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Talk Title"&lt;/span&gt; 
        &lt;span class="na"&gt;validation=&lt;/span&gt;&lt;span class="s"&gt;"required"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"textarea"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Talk Brief"&lt;/span&gt; 
        &lt;span class="na"&gt;validation=&lt;/span&gt;&lt;span class="s"&gt;"required|length:100"&lt;/span&gt;
        &lt;span class="na"&gt;help=&lt;/span&gt;&lt;span class="s"&gt;"What is your talk about?"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Talk Track"&lt;/span&gt;
        &lt;span class="na"&gt;help=&lt;/span&gt;&lt;span class="s"&gt;"Which track are you submitting for?"&lt;/span&gt;
        &lt;span class="na"&gt;:options=&lt;/span&gt;&lt;span class="s"&gt;"['Development', 'Testing', 'Leadership']"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"step"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"referral"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Ask the user to share how they heard about us --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Thank you for taking the time to submit your talk&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;If you don't mind we'd love to know how you heard about VueUniverse.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; 
        &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"How did you hear about VueUniverse?"&lt;/span&gt; 
        &lt;span class="na"&gt;:options=&lt;/span&gt;&lt;span class="s"&gt;"['Online Ad', 'Friend or Coworker', 'Search Results', 'Other']"&lt;/span&gt;
      &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there we go! One component, &lt;code&gt;FormKit&lt;/code&gt;, with a consistent API and we've got ourselves a working multi-step form with validation! &lt;/p&gt;

&lt;p&gt;(for the best experience open this example in a new tab)&lt;br&gt;
&lt;iframe src="https://codesandbox.io/embed/eloquent-lewin-ef3evc?module=%2Fsrc%2Fcomponents%2FMultiStepForm.vue&amp;amp;view=preview"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;That's great! But there's two things we can change to make it better.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since we're using the &lt;code&gt;multi-step&lt;/code&gt; input as our entire form experience it would be great to have the submit button be inside the last step rather than external to the &lt;code&gt;multi-step&lt;/code&gt; input.&lt;/li&gt;
&lt;li&gt;We're asking users to go through a set flow, so it would be great if our tabs indicated progress. Additionally it would be great if we prevented the user from navigating to the next step until the current step is completed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thankfully, these are both very easy changes to implement.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First we need to set &lt;code&gt;:actions="false"&lt;/code&gt; on our wrapping &lt;code&gt;form&lt;/code&gt; type &lt;code&gt;FormKit&lt;/code&gt; component to disable the default submit button. Then, using the &lt;code&gt;stepNext&lt;/code&gt; slot we can insert our own submit button inside the last step in our multi-step form.&lt;/li&gt;
&lt;li&gt;Second, we need to use the &lt;code&gt;tab-style="progress"&lt;/code&gt; and &lt;code&gt;allow-incomplete="false"&lt;/code&gt; props to show progress-style tabs and prevent the user from freely navigating through steps until validation is passed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the relevant sections of our form with those changes implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- remove default actions on the form --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;
  &lt;span class="na"&gt;:actions=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Set new props on our multi-step --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; 
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"multi-step"&lt;/span&gt;
    &lt;span class="na"&gt;tab-style=&lt;/span&gt;&lt;span class="s"&gt;"progress"&lt;/span&gt;
    &lt;span class="na"&gt;:allow-incomplete=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="c"&gt;&amp;lt;!-- In our last step, add a submit button --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"step"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"referral"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      ...
      &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;#stepNext&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And again, that's it! FormKit takes care of the rest for us. Here is our new and improved multi-step form experience after changing those 6 lines of code.&lt;/p&gt;

&lt;p&gt;(for the best experience open this example in a new tab)&lt;br&gt;
&lt;iframe src="https://codesandbox.io/embed/formkit-multi-step-form-phase-2-7hiu6b?module=%2Fsrc%2Fcomponents%2FMultiStepForm.vue"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Best of all this form has accessible markup, built-in validation, and much more that we didn't have to worry about ourselves thanks to the underlying FormKit component architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Quick, easy, powerful. Implementing a multi-step form in your project has never been simpler.&lt;/p&gt;

&lt;p&gt;By leveraging FormKit in your Vue projects you can supercharge your form development and build rich and complex user-experiences in a fraction of the time — for free.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3ov9jWu7BuHufyLs7m/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3ov9jWu7BuHufyLs7m/giphy.gif" alt="Developer after building a multi-step in 5 minutes" width="415" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to learn more about FormKit and how it can help with form structure, validation, accessibility, and more? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check out the multi-step docs at &lt;a href="https://formkit.com/plugins/multi-step"&gt;https://formkit.com/plugins/multi-step&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Join the FormKit Discord community for support and to meet others using FormKit in their own projects: &lt;a href="https://discord.gg/2q3UZkUQbR"&gt;https://discord.gg/2q3UZkUQbR&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>vue</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Creating a Tailwind CSS theme for FormKit</title>
      <dc:creator>Andrew Boyd</dc:creator>
      <pubDate>Thu, 10 Mar 2022 20:30:16 +0000</pubDate>
      <link>https://dev.to/andrewboyd/creating-a-tailwind-css-theme-for-formkit-45o4</link>
      <guid>https://dev.to/andrewboyd/creating-a-tailwind-css-theme-for-formkit-45o4</guid>
      <description>&lt;h2&gt;
  
  
  FormKit ❤️ Tailwind CSS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://formkit.com"&gt;FormKit&lt;/a&gt; ships with first-class support for &lt;a href="https://tailwindcss.com"&gt;Tailwind CSS&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For small projects – using Tailwind CSS with FormKit can be as easy as using the &lt;a href="https://formkit.com/essentials/styling#section-key-class-props"&gt;inline class props&lt;/a&gt; available on the &lt;code&gt;&amp;lt;FormKit /&amp;gt;&lt;/code&gt; component. For more advanced use cases FormKit ships with a package (&lt;code&gt;@formkit/tailwindcss&lt;/code&gt;) that makes creating a robust Tailwind CSS theme a breeze.&lt;/p&gt;

&lt;p&gt;The following guide will walk you through both processes and show you how they can work together to provide incredible flexibility when styling your FormKit inputs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This guide assumes you are using a standard Vue 3 build tool like Vite, Nuxt 3, or Vue CLI that will allow you to import &lt;code&gt;.vue&lt;/code&gt; single file components.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Inline usage for simple use cases
&lt;/h2&gt;

&lt;p&gt;If FormKit represents a small portion of your project — say a single contact form on a brochure website — then you'll likely be able to apply all the styling you need using the &lt;a href="https://formkit.com/essentials/styling#section-key-class-props"&gt;&lt;code&gt;${sectionKey}-class&lt;/code&gt; props&lt;/a&gt; or the &lt;a href="https://formkit.com/essentials/styling#classes-prop"&gt;&lt;code&gt;classes&lt;/code&gt; prop&lt;/a&gt; available on the &lt;code&gt;&amp;lt;FormKit /&amp;gt;&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Here's a contact form styled using only the &lt;code&gt;classes&lt;/code&gt; prop for a FormKit form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;
    &lt;span class="na"&gt;:actions=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
    &lt;span class="na"&gt;:config=&lt;/span&gt;&lt;span class="s"&gt;"{
      // config override applies to all nested FormKit components
      classes: {
        outer: 'mb-5',
        label: 'block mb-1 font-bold text-sm',
        input: 'text-gray-800 mb-1 w-full',
        help: 'text-xs text-gray-500',
        message: 'text-red-500 text-xs',
      },
    }"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
      &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;
      &lt;span class="na"&gt;help=&lt;/span&gt;&lt;span class="s"&gt;"First and last name"&lt;/span&gt;
      &lt;span class="na"&gt;validation=&lt;/span&gt;&lt;span class="s"&gt;"required"&lt;/span&gt;
      &lt;span class="na"&gt;:classes=&lt;/span&gt;&lt;span class="s"&gt;"{
        input: 'border border-gray-400 py-1 px-2 rounded-md',
      }"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
      &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt;
      &lt;span class="na"&gt;validation=&lt;/span&gt;&lt;span class="s"&gt;"required|email"&lt;/span&gt;
      &lt;span class="na"&gt;:classes=&lt;/span&gt;&lt;span class="s"&gt;"{
        input: 'border border-gray-400 py-1 px-2 rounded-md',
      }"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"textarea"&lt;/span&gt;
      &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Message"&lt;/span&gt;
      &lt;span class="na"&gt;validation=&lt;/span&gt;&lt;span class="s"&gt;"required|length:10"&lt;/span&gt;
      &lt;span class="na"&gt;:classes=&lt;/span&gt;&lt;span class="s"&gt;"{
        input: 'border border-gray-400 py-1 px-2 rounded-md',
      }"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;
      &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Submit"&lt;/span&gt;
      &lt;span class="na"&gt;:classes=&lt;/span&gt;&lt;span class="s"&gt;"{
        outer: 'mb-0',
        input: 'bg-blue-500 text-white font-bold py-2 px-3 rounded-md w-auto',
      }"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/FormKit&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/formkit-inline-tailwind-example?ctl=1&amp;amp;embed=1&amp;amp;file=src/components/ContactForm.vue&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is a low-barrier way to apply Tailwind CSS styles to your FormKit forms. But what if you have multiple forms? Copy-pasting class lists between components is not ideal and can lead to inadvertent variations in styling across your project over time.&lt;/p&gt;

&lt;p&gt;Let's explore how we can apply Tailwind CSS classes globally to &lt;em&gt;all&lt;/em&gt; FormKit inputs within our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;@formkit/tailwindcss&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;FormKit ships with a first-party package called &lt;code&gt;@formkit/tailwindcss&lt;/code&gt; that makes it simple to create a Tailwind CSS theme for FormKit.&lt;/p&gt;

&lt;p&gt;This package allows you to author your theme as a JavaScript object grouped by input &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;sectionKey&lt;/code&gt;. Additionally, it exposes a number of Tailwind CSS variants based on FormKit state such as &lt;code&gt;formkit-invalid:&lt;/code&gt; and &lt;code&gt;formkit-disabled:&lt;/code&gt; which allow you to dynamically change your input styling.&lt;/p&gt;

&lt;p&gt;To get started we first need to add the package to our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @formkit/tailwindcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the &lt;code&gt;@formkit/tailwindcss&lt;/code&gt; plugin to our project's &lt;code&gt;tailwind.config.js&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Import &lt;code&gt;generateClasses&lt;/code&gt; from &lt;code&gt;@formkit/tailwindcss&lt;/code&gt; and use it where we define our FormKit config options.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tailwind.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&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;@formkit/tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&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;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js&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;createApp&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;vue&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;App&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;./App.vue&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;plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&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;@formkit/vue&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;generateClasses&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;@formkit/tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../dist/index.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// wherever your Tailwind styles exist&lt;/span&gt;

&lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;generateClasses&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="c1"&gt;// our theme will go here.&lt;/span&gt;
          &lt;span class="c1"&gt;// ...&lt;/span&gt;
          &lt;span class="c1"&gt;// text: {&lt;/span&gt;
          &lt;span class="c1"&gt;//   label: 'font-bold text-gray-300',&lt;/span&gt;
          &lt;span class="c1"&gt;//   ...&lt;/span&gt;
          &lt;span class="c1"&gt;// }&lt;/span&gt;
          &lt;span class="c1"&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&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;



&lt;p&gt;Once this setup is complete we are ready to begin writing our Tailwind CSS theme!&lt;/p&gt;

&lt;h2&gt;
  
  
  Our first Tailwind CSS input
&lt;/h2&gt;

&lt;p&gt;To start, let's apply some classes to a &lt;code&gt;text&lt;/code&gt; style input. This will cover a large surface area because we'll be able to easily re-use these styles on other text-like inputs such as &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;To specifically target &lt;code&gt;text&lt;/code&gt; inputs we'll create a &lt;code&gt;text&lt;/code&gt; key in our theme object and then apply classes to each &lt;code&gt;sectionKey&lt;/code&gt; as needed.&lt;/p&gt;

&lt;p&gt;Here is a &lt;code&gt;text&lt;/code&gt; input with Tailwind CSS classes applied using our default FormKit config values:&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;createApp&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;vue&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;App&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;./App.vue&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultConfig&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;@formkit/vue&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generateClasses&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;@formkit/tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;generateClasses&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mb-5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block mb-1 font-bold text-sm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bg-white max-w-md border border-gray-400 rounded-lg mb-1 overflow-hidden focus-within:border-blue-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w-full h-10 px-3 bg-transparent border-none focus:outline-none text-base text-gray-700 placeholder-gray-400 focus:outline-none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-xs text-gray-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list-none p-0 mt-1 mb-0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-red-500 mb-1 text-xs&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;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="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&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;



&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/formkit-tailwind-global-config-input?ctl=1&amp;amp;embed=1&amp;amp;file=src/main.js&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Using variants
&lt;/h2&gt;

&lt;p&gt;That's looking good! But it's fairly static at the moment. It would be nice if we could react with different styles based on the state of our inputs.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@formkit/tailwindcss&lt;/code&gt; package provides a number of variants you can use in your class lists to dynamically respond to input and form state.&lt;/p&gt;

&lt;p&gt;The currently shipped variants are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;formkit-disabled:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-invalid:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-errors:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-complete:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-loading:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-submitted:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-multiple:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-action:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-message-validation:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;formkit-message-error:&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use these variant the same way you would use built-in Tailwind CSS variants such as &lt;code&gt;dark:&lt;/code&gt; and &lt;code&gt;hover:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's add some variants for &lt;code&gt;formkit-invalid&lt;/code&gt; and &lt;code&gt;formkit-disabled&lt;/code&gt; to our text input styles.&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mb-5 formkit-disabled:opacity-40&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block mb-1 font-bold text-sm formkit-invalid:text-red-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
      max-w-md
      border border-gray-400
      rounded-lg
      mb-1
      overflow-hidden
      focus-within:border-blue-500
      formkit-invalid:border-red-500
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w-full h-10 px-3 border-none text-base text-gray-700 placeholder-gray-400 focus:outline-none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-xs text-gray-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list-none p-0 mt-1 mb-0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-red-500 mb-1 text-xs&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/formkit-tailwind-global-config-input-n53j76?ctl=1&amp;amp;embed=1&amp;amp;file=src/theme.js&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a full theme
&lt;/h2&gt;

&lt;p&gt;Now we're cooking! To create a comprehensive theme we need to define class lists for the &lt;code&gt;sectionKeys&lt;/code&gt; of all of the other input types we'll use in our project.&lt;/p&gt;

&lt;p&gt;Before we go too far though, there are some improvements we can make. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;generateClasses&lt;/code&gt; function in &lt;code&gt;@formkit/tailwindcss&lt;/code&gt; allows for a special input type key called &lt;code&gt;global&lt;/code&gt; that will apply to &lt;em&gt;all&lt;/em&gt; inputs. This is helpful for targeting &lt;code&gt;sectionKeys&lt;/code&gt; such as &lt;code&gt;help&lt;/code&gt; and &lt;code&gt;messages&lt;/code&gt; that are often styled identically across all input types within a project.&lt;/p&gt;

&lt;p&gt;Let's create class list definitions for &lt;em&gt;all&lt;/em&gt; input types included in FormKit. We'll group common types of inputs into "classifications" to avoid being too repetitive.&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="c1"&gt;// We'll create some re-useable definitions&lt;/span&gt;
&lt;span class="c1"&gt;// because many input types are identical&lt;/span&gt;
&lt;span class="c1"&gt;// in how we want to style them.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block mb-1 font-bold text-sm formkit-invalid:text-red-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max-w-md border border-gray-400 formkit-invalid:border-red-500 rounded-lg mb-1 overflow-hidden focus-within:border-blue-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w-full h-10 px-3 border-none text-base text-gray-700 placeholder-gray-400&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;boxClassification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;fieldset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max-w-md border border-gray-400 rounded-md px-2 pb-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;font-bold text-sm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex items-center mb-1 cursor-pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mb-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form-check-input appearance-none h-5 w-5 mr-2 border border-gray-500 rounded-sm bg-white checked:bg-blue-500 focus:outline-none focus:ring-0 transition duration-200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-sm text-gray-700 mt-1&lt;/span&gt;&lt;span class="dl"&gt;'&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;buttonClassification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mb-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bg-blue-500 hover:bg-blue-700 text-white text-sm font-normal py-3 px-5 rounded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// We'll export our definitions using our above&lt;/span&gt;
&lt;span class="c1"&gt;// classification templates and declare&lt;/span&gt;
&lt;span class="c1"&gt;// one-offs and overrides as needed.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// the global key will apply to _all_ inputs&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mb-5 formkit-disabled:opacity-50&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;help&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-xs text-gray-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list-none p-0 mt-1 mb-0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-red-500 mb-1 text-xs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;button&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;buttonClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block mb-1 font-bold text-sm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w-16 h-8 appearance-none cursor-pointer border border-gray-300 rounded-md mb-2 p-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;datetime-local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boxClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block mb-1 font-bold text-sm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max-w-md cursor-pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-gray-600 text-sm mb-1 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:bg-blue-500 file:text-white hover:file:bg-blue-600&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;noFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block text-gray-800 text-sm mb-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fileItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block flex text-gray-800 text-sm mb-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;removeFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ml-auto text-blue-500 text-sm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;radio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// if we want to override a given sectionKey&lt;/span&gt;
    &lt;span class="c1"&gt;// from a classification we can do a spread&lt;/span&gt;
    &lt;span class="c1"&gt;// of the default value along with a new&lt;/span&gt;
    &lt;span class="c1"&gt;// definition for our target sectionKey.&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;boxClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boxClassification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rounded-sm&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;rounded-full&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="na"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max-w-md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form-range appearance-none w-full h-2 p-0 bg-gray-200 rounded-full focus:outline-none focus:ring-0 focus:shadow-none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;buttonClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;textarea&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="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block w-full h-32 px-3 border-none text-base text-gray-700 placeholder-gray-400 focus:shadow-outline&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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;week&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;textClassification&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;&lt;iframe src="https://stackblitz.com/edit/formkit-tailwind-global-config-theme?ctl=1&amp;amp;embed=1&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;file=src/theme.js&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Selective overrides
&lt;/h2&gt;

&lt;p&gt;And there we have it! All FormKit inputs are now styled with Tailwind CSS classes across our entire project.&lt;/p&gt;

&lt;p&gt;If we ever need to override any specific one-offs within our project, we can do so using the &lt;a href="https://dev.to/essentials/styling#section-key-class-props"&gt;section-key class props&lt;/a&gt; or the &lt;a href="https://dev.to/essentials/styling#classes-prop"&gt;classes&lt;/a&gt; prop on a given &lt;code&gt;FormKit&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;Of particular importance when performing an override is the &lt;a href="https://dev.to/essentials/styling#resetting-classes"&gt;&lt;code&gt;$reset&lt;/code&gt; modifier&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;When the FormKit class system encounters a class named &lt;code&gt;$reset&lt;/code&gt; it will discard the current class list for the given sectionKey and only collect class names that occur after the &lt;code&gt;$reset&lt;/code&gt; class. This is helpful for systems like Tailwind CSS where it can be cumbersome to override a large number of classes when you need to deviate from your base theme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
    &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"I use the global theme we defined"&lt;/span&gt;
    &lt;span class="na"&gt;help=&lt;/span&gt;&lt;span class="s"&gt;"I play by the rules"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;FormKit&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
    &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"I'm special and have a $reset and custom styles"&lt;/span&gt;
    &lt;span class="na"&gt;help=&lt;/span&gt;&lt;span class="s"&gt;"I'm a rebel"&lt;/span&gt;
    &lt;span class="na"&gt;label-class=&lt;/span&gt;&lt;span class="s"&gt;"$reset italic text-lg text-red-500"&lt;/span&gt;
    &lt;span class="na"&gt;help-class=&lt;/span&gt;&lt;span class="s"&gt;"$reset font-bold text-md text-purple-800"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/formkit-tailwind-global-config-overrides?ctl=1&amp;amp;embed=1&amp;amp;file=src/components/ExampleInput.vue&amp;amp;hideExplorer=1&amp;amp;hideNavigation=1&amp;amp;view=preview" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;This guide has walked through creating a Tailwind CSS theme for all input types included in FormKit, but there is still more that could be done!&lt;/p&gt;

&lt;p&gt;Here are some ways to take the above guide even further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add dark-mode support using the built-in Tailwind CSS &lt;code&gt;dark:&lt;/code&gt; modifier.&lt;/li&gt;
&lt;li&gt;Combine multiple variants such as &lt;code&gt;formkit-invalid:formkit-submitted:&lt;/code&gt; to add extra emphasis to invalid fields when a user tries to submit an incomplete form.&lt;/li&gt;
&lt;li&gt;Publish your theme as an &lt;code&gt;npm&lt;/code&gt; package for easy importing and sharing between projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to dive in deeper into FormKit there's plenty to learn about the &lt;a href="https://dev.to/advanced/core"&gt;core internals&lt;/a&gt; of the framework as well as &lt;a href="https://dev.to/advanced/schema"&gt;the FormKit schema&lt;/a&gt; which allows generating forms from JSON with conditionals, expressions, and more!&lt;/p&gt;

&lt;p&gt;Now go forth and make beautiful forms!&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Details Matter: Add a Visual Grid System to your Front-end Development Process</title>
      <dc:creator>Andrew Boyd</dc:creator>
      <pubDate>Tue, 07 Jul 2020 15:49:20 +0000</pubDate>
      <link>https://dev.to/andrewboyd/details-matter-add-a-visual-grid-system-to-your-front-end-development-process-fg3</link>
      <guid>https://dev.to/andrewboyd/details-matter-add-a-visual-grid-system-to-your-front-end-development-process-fg3</guid>
      <description>&lt;p&gt;Front-end engineers are responsible for translating visual designs into working code for the web. The target that we aim for is a faithful translation of source design files into code. The holy grail would be to put a screenshot of the design and a screenshot of the accompanying final product side-by-side and be unable to tell which was which.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lNYpuK2U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lxjcket4q0urgbt6dkl1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lNYpuK2U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lxjcket4q0urgbt6dkl1.jpg" alt="Side by side browser and design file" width="880" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above are screenshots of the design file for &lt;a href="https://www.outdoordreamsva.com"&gt;Outdoor Dreams&lt;/a&gt; alongside the final browser build (with the front-end visual grid turned on). Are you able to tell which one is from the browser and which one is from Sketch?&lt;/p&gt;

&lt;p&gt;As front-end engineers, to varying degrees, we often miss the mark. Sometimes it's because the designs themselves were unfeasible — lacking in consistency and not lending themselves to being faithfully reproduced within a given project’s budget. Other times it’s because we set ourselves up for failure by allowing guesswork to enter our process through poor architecture. It's time to level up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evolution of the digital design ecosystem
&lt;/h3&gt;

&lt;p&gt;The tooling available to digital designers has evolved by leaps and bounds over the past several years. We’ve gone from the dark days of using print-focused design tools such as Adobe Photoshop to create web layouts to witnessing an explosion of digital-native design tools in the form of Sketch, Adobe XD, Figma and more. Beyond that, the design language of the web itself has evolved — more and more designers are breaking the bounds of what audiences have come to expect from layouts on the web.&lt;/p&gt;

&lt;p&gt;There was a time as an engineer where you’d be safe to assume a design would map to a 12-column grid and any number of off-the-shelf CSS grid systems would suit your needs. 12-columns has been historically considered an ideal number of columns to work with due to 12 being such a highly divisible number. Many tools emerged onto the scene under the assumption that whatever you wanted to build could be suitably done with 12 columns.&lt;/p&gt;

&lt;p&gt;In present-day, however, designers have declared “conventional wisdom be damned!” and &lt;strong&gt;the days of the 12-column one-size-fits-all layout system are gone&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Good! More power to them. It’s time to rethink our preconceived limitations for layout on the web and allow it to mature into the editorial design-forward platform we all know it’s capable of being. As front-end engineers, it’s our responsibility to rise to the challenge and ensure that we’re equipping ourselves to hit the mark being set for us by our designer colleagues. But how do we remove the guesswork and give ourselves the tooling necessary to faithfully reproduce the designs we are tasked with developing?&lt;/p&gt;

&lt;h3&gt;
  
  
  A flawed process
&lt;/h3&gt;

&lt;p&gt;The current standards for a typical front-end development process are not ideal. We reference design files as we write our code — comparing the designs and the browser results side-by-side via visual inspection. This process involves tinkering with the design file to get the exact measurements you need, writing the code to produce those measurements in the browser, and then comparing the results visually to confirm they look correct — or at least correct within tolerable approximation. We spend a large amount of our time adjusting our code to accurately represent provided designs but when it's time to verify the results we do so via error-prone visual inspection.&lt;/p&gt;

&lt;p&gt;This sucks. It's time to level up our process so that we can produce better results. &lt;strong&gt;“Good enough” isn't good enough.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The designs we reference are painstakingly produced with a precise grid and visual overlays to assist the designer. In the browser, the absence of those helpful visual indicators means that small imperfections often go overlooked (or worse, ignored). Why don’t we bring those visual indicators into the browser as part of our engineering process so that we can better hit the mark of 1:1 parity between design and front-end development? It’s a good question and one that we’re actively addressing at &lt;a href="https://www.wearebraid.com"&gt;Braid&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Now you see it
&lt;/h3&gt;

&lt;p&gt;Our answer is this: Precisely recreate the visual grid overlay in the browser and use a system that enforces it. The designer you’re collaborating with deliberately configured the grid, intentionally adhered to it, at times tastefully deviated from it, and a part of their soul withers if you completely ignore it. Give yourself the advantage of removing the guesswork. See for yourself when you've faithfully reproduced a design.&lt;/p&gt;

&lt;p&gt;To assist our own team with this we authored &lt;a href="https://github.com/wearebraid/griddle"&gt;Griddle&lt;/a&gt;, an open-source set of .scss functions and mixins that allow engineers to configure a flexible visual grid system for their projects. Griddle comes out of the box with a Vue component that adds a visual overlay to your project in the browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RAHB7zkk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hqb6kppvq79jj987ohbu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RAHB7zkk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hqb6kppvq79jj987ohbu.gif" alt="animated demo of Griddle" width="600" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short (read the &lt;code&gt;readme.md&lt;/code&gt; for the long version), Griddle aspires to make minimal assumptions about your grid system. Your designer provided you with a 14-column grid with a 72px / 32px column-to-gutter ratio at the largest breakpoint? No problem. Configure your overrides for Griddle in your own &lt;code&gt;.scss&lt;/code&gt; files using the layout information found in the source design file.&lt;/p&gt;

&lt;p&gt;Once installed and configured, you'll be able to toggle the Griddle overlay in your project (&lt;code&gt;control + shift + L&lt;/code&gt;) revealing an identical set of visual column indicators in your browser as the ones seen in your design program. You can try it out in a few different configurations &lt;a href="https://www.outdoordreamsva.com/"&gt;here&lt;/a&gt;, &lt;a href="https://www.gardenary.com/#/"&gt;here&lt;/a&gt;, or on our own site &lt;a href="https://www.wearebraid.com/home"&gt;here&lt;/a&gt; if you want to see it in action for yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;By equipping ourselves with the same visual grid overlay being used by our designer colleagues we remove almost all of the guesswork inherent to visual side-by-side inspection.&lt;/p&gt;

&lt;p&gt;Griddle itself is nothing magical, it’s a fixed-position overlay being calculated with some basic math from your provided configuration. Use it, or write your own. But no matter what you do, ensure that you’re taking steps to set yourself up for success. Rise to the occasion and aspire to faithfully reproduce the work being entrusted to us as front-end engineers. 1:1 is the target, and in many cases, there’s no reason to not hit that mark.&lt;/p&gt;




&lt;p&gt;Oh, and in case you’re curious, in the comparison screenshot at the beginning of the article, the browser version is on the left. 🙂&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>design</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
