<?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: Mustapha Abdul-Rasaq</title>
    <description>The latest articles on DEV Community by Mustapha Abdul-Rasaq (@geekmaros).</description>
    <link>https://dev.to/geekmaros</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%2F75752%2Fe31e290c-0ca5-43c4-8a53-14f6b023c3bb.jpeg</url>
      <title>DEV Community: Mustapha Abdul-Rasaq</title>
      <link>https://dev.to/geekmaros</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geekmaros"/>
    <language>en</language>
    <item>
      <title>Fixing Tailwind CSS Autocomplete in RubyMine (Rails 8 + Tailwind CSS 4)</title>
      <dc:creator>Mustapha Abdul-Rasaq</dc:creator>
      <pubDate>Tue, 07 Oct 2025 16:25:40 +0000</pubDate>
      <link>https://dev.to/geekmaros/fixing-tailwind-css-autocomplete-in-rubymine-rails-8-tailwind-css-4-1n5l</link>
      <guid>https://dev.to/geekmaros/fixing-tailwind-css-autocomplete-in-rubymine-rails-8-tailwind-css-4-1n5l</guid>
      <description>&lt;h2&gt;
  
  
  Fixing Tailwind CSS Autocomplete in RubyMine (Rails 8 + Tailwind CSS 4)
&lt;/h2&gt;

&lt;p&gt;If you’ve recently created a Rails 8 app with Tailwind CSS 4 and noticed that Tailwind class autocomplete doesn’t work in RubyMine  you’re not alone.&lt;/p&gt;

&lt;p&gt;This happens because RubyMine’s Tailwind CSS plugin expects a Node-based Tailwind CLI, while Rails now bundles Tailwind via cssbundling-rails, which doesn’t rely on Node or npm by default.&lt;/p&gt;

&lt;p&gt;Good news: there’s a clean workaround.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: How Rails sets up Tailwind by default&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you create a new Rails app with the -c tailwind flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails new myapp -c tailwind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rails automatically:&lt;br&gt;
    • Installs Tailwind via cssbundling-rails.&lt;br&gt;
configuration).&lt;br&gt;
    • Creates a app/assets/stylesheets/tailwind folder containing application.css.&lt;/p&gt;

&lt;p&gt;That application.css file includes this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@import "tailwindcss";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run &lt;code&gt;bin/dev&lt;/code&gt;, Rails compiles Tailwind through its build pipeline (not Node), so Tailwind works perfectly in the browser.&lt;/p&gt;

&lt;p&gt;However…&lt;br&gt;
RubyMine’s Tailwind CSS plugin doesn’t know this setup yet  so it doesn’t trigger autocomplete for class names inside your .erb, .html, or .turbo_stream.erb files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: The Fix for RubyMine Autocomplete&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To make RubyMine recognize Tailwind in your Rails 8 project, add one or both of the following tweaks.&lt;/p&gt;

&lt;p&gt;Option A (Recommended – Minimal Fix)&lt;/p&gt;

&lt;p&gt;Create a minimal package.json file in your project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo '{"devDependencies": {"tailwindcss": "latest"}}' &amp;gt; package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps RubyMine detect that Tailwind exists, and autocomplete should start working immediately after restarting the IDE.&lt;/p&gt;

&lt;p&gt;Option B (Optional – Full CLI Link)&lt;/p&gt;

&lt;p&gt;If autocomplete still doesn’t trigger, you can make RubyMine think Tailwind CLI is installed via Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p ./node_modules/tailwindcss/lib
ln -s tailwindcss node_modules/tailwindcss/lib/cli.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simply creates a soft link where RubyMine expects the Tailwind binary to live,  no npm installation required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Restart RubyMine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve done either step, restart RubyMine (or invalidate caches).&lt;br&gt;
You should now get full Tailwind class suggestions and color previews when typing inside .html.erb and .html+turbo_stream.erb templates.&lt;/p&gt;

&lt;p&gt;Your tailwind auto-suggest class names should show&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%2Fywhgrbvk9cntaixbna95.png" 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%2Fywhgrbvk9cntaixbna95.png" alt="rails code showing tailwind suggestion classnames" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Credits&lt;/p&gt;

&lt;p&gt;Big thanks to &lt;a href="https://www.maragu.dev/" rel="noopener noreferrer"&gt;Markus Wüstenberg&lt;/a&gt;  and the &lt;a href="https://youtrack.jetbrains.com/issue/WEB-55647/Support-Tailwind-css-autocompletion-using-standalone-tailwind-CLI#focus=Comments-27-10957961.0-0" rel="noopener noreferrer"&gt;JetBrains YouTrack thread&lt;/a&gt; for highlighting this workaround.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>rubymine</category>
      <category>jetbrain</category>
    </item>
    <item>
      <title>Dynamically Add/Remove input fields using Vuejs</title>
      <dc:creator>Mustapha Abdul-Rasaq</dc:creator>
      <pubDate>Fri, 20 Nov 2020 23:57:54 +0000</pubDate>
      <link>https://dev.to/geekmaros/dynamically-add-remove-input-fields-using-vuejs-3d4d</link>
      <guid>https://dev.to/geekmaros/dynamically-add-remove-input-fields-using-vuejs-3d4d</guid>
      <description>&lt;p&gt;We all know how awesome Vuejs is as a frontend frame work and we are going to be exploring one of it's awesomeness by showing how to dynamically add or remove fields.  &lt;br&gt;
To ensure you get the best of this article, here are some assumptions. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;you know basic javascript such as writing a &lt;code&gt;function()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;you know what a Vuejs Single File component is (trust me even a beginner understands this 😉 )&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fht9quwte1go4ab8gbel9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fht9quwte1go4ab8gbel9.png" alt="SFC.png" width="800" height="651"&gt;&lt;/a&gt; &lt;br&gt;
 I am using TailwindCSS to handle styling so don't fret when you see some class names.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Simple Logic.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;create a variable = phoneNumbers (an Array) that store all input fields&lt;/li&gt;
&lt;li&gt;a click handler to addField(inputField), this basically push into the array,&lt;/li&gt;
&lt;li&gt;a click handler to removeField(inputFieldIndex), this removes the index of the inputField from the array&lt;/li&gt;
&lt;li&gt;use a v-for directive to loop through the input fields to display them.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Let's get our hands dirty.
&lt;/h3&gt;

&lt;p&gt;(1) Let's create a form with an input field&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;section class="w-full flex justify-center items-center my-10"&amp;gt;
    &amp;lt;form class=""&amp;gt;
      &amp;lt;div class="form-group"&amp;gt;
        &amp;lt;label class="text-gray-600 font-semibold text-lg"&amp;gt;Phone Number&amp;lt;/label&amp;gt;
        &amp;lt;div class="input wrapper flex items-center"&amp;gt;
          &amp;lt;input
            type="text"
            class="h-10 rounded-lg outline-none p-2"
            placeholder=" Enter Phone Number"
          /&amp;gt;
          &amp;lt;!--          Add Svg Icon--&amp;gt;
          &amp;lt;svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width="24"
            height="24"
            class="ml-2 cursor-pointer"
          &amp;gt;
            &amp;lt;path fill="none" d="M0 0h24v24H0z" /&amp;gt;
            &amp;lt;path
              fill="green"
              d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
            /&amp;gt;
          &amp;lt;/svg&amp;gt;

          &amp;lt;!--          Remove Svg Icon--&amp;gt;
          &amp;lt;svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width="24"
            height="24"
            class="ml-2 cursor-pointer"
          &amp;gt;
            &amp;lt;path fill="none" d="M0 0h24v24H0z" /&amp;gt;
            &amp;lt;path
              fill="#EC4899"
              d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
            /&amp;gt;
          &amp;lt;/svg&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
  &amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb688etoi2owtjor08x0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb688etoi2owtjor08x0.png" alt="htmlpage1.png" width="675" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(2) In the data object, we add a key called phoneNumbers which is an array of object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
//Your Javascript lives within the Script Tag
export default {
  name: "AddRemove",
  data() {
    return {
      phoneNumbers: [{ phone: "" }],
    };
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(3) using v-for directive, we can render the each input field in the phoneNumbers array and also bind a key to each rendered input field.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can use the v-for directive to render a list of items based on an array. The v-for directive requires a special syntax in the form of item in items, where items is the source data array and item is an alias for the array element being iterated on:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   &amp;lt;label class="text-gray-600 font-semibold text-lg"&amp;gt;Phone Number&amp;lt;/label&amp;gt;
        &amp;lt;div
          v-for="(input, index) in phoneNumbers"
          :key="`phoneInput-${index}`"
          class="input wrapper flex items-center"
        &amp;gt;
          &amp;lt;input
            type="text"
            class="h-10 rounded-lg outline-none p-2"
            placeholder=" Enter Phone Number"
          /&amp;gt;
          &amp;lt;!--          Add Svg Icon--&amp;gt;
          &amp;lt;svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width="24"
            height="24"
            class="ml-2 cursor-pointer"
          &amp;gt;
            &amp;lt;path fill="none" d="M0 0h24v24H0z" /&amp;gt;
            &amp;lt;path
              fill="green"
              d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
            /&amp;gt;
          &amp;lt;/svg&amp;gt;

          &amp;lt;!--          Remove Svg Icon--&amp;gt;
          &amp;lt;svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width="24"
            height="24"
            class="ml-2 cursor-pointer"
          &amp;gt;
            &amp;lt;path fill="none" d="M0 0h24v24H0z" /&amp;gt;
            &amp;lt;path
              fill="#EC4899"
              d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
            /&amp;gt;
          &amp;lt;/svg&amp;gt;
        &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(4) using v-model directive, we can enable two way binding on form elements to get form element data. Don't forget phoneNumbers variable is an array of object, there for we can use the dot(.) notation to access object in the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;input 
               v-model="input.phone"
               type="text" 
               class="h-10 rounded-lg outline-none p-2" 
               placeholder=" Enter Phone Number"     
          /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(5) create the various Method Event Handlers (addField and removeField()). in the code below, we passed fieldType as a second args for addField(). fieldType is the input category eg phoneNumbers, emailAddresses, or any other (array) field you want to dynamically add or remove&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
export default {
  name: "AddRemove",
  data() {
    return {
      phoneNumbers: [{ phone: "" }],
    };
  },
  methods: {
    addField(value, fieldType) {
      fieldType.push({ value: "" });
    },
    removeField(index, fieldType) {
      fieldType.splice(index, 1);
    },
  },
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(6) Finally we bind the Handlers to our add and remove icons. &lt;br&gt;
One last thing, let us conditionally render the delete button such that it only shows when the number of fields are greater than 1. &lt;br&gt;
This can done using v-show directive where we can write a simple js expression&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;!--          Add Svg Icon--&amp;gt;
          &amp;lt;svg

            @click="addField(input, phoneNumbers)"
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width="24"
            height="24"
            class="ml-2 cursor-pointer"
          &amp;gt;
            &amp;lt;path fill="none" d="M0 0h24v24H0z" /&amp;gt;
            &amp;lt;path
              fill="green"
              d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
            /&amp;gt;
          &amp;lt;/svg&amp;gt;

          &amp;lt;!--          Remove Svg Icon--&amp;gt;
          &amp;lt;svg
            v-show="phoneNumbers.length &amp;gt; 1"
            @click="removeField(index, phoneNumbers)"
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width="24"
            height="24"
            class="ml-2 cursor-pointer"
          &amp;gt;
            &amp;lt;path fill="none" d="M0 0h24v24H0z" /&amp;gt;
            &amp;lt;path
              fill="#EC4899"
              d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
            /&amp;gt;
          &amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx876ndzlx7mraavp48bv.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/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx876ndzlx7mraavp48bv.gif" alt="ar.gif" width="690" height="388"&gt;&lt;/a&gt;&lt;br&gt;
There you go, you should be able to dynamically add and remove fields using vuejs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gracias&lt;/em&gt; for reading this far, i know it was quite long but worth it.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
