[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-content-vue-2-to-vue-3-a-nearly-painless-approach":3},"\u003Cp>Recently, I had the pleasure of updating a Vue 2 project, that had quite a \"vue\" years under its belt. There exist many guides out there, on how to do that. To be honest, most of them are bullshit, and it seems as if every guide out there just copied the official docs for migrating - without any thought. \u003C\u002Fp>\u003Cp>I had to update a project, that used Vue 2.6.11, Vuetify 2.2.6 and Typescript 3.5 as well as many, many other packages. While updating I had to constantly adapt to new Typescript rules, changed Vue internal APIs as well as changed Vuetify components.\u003C\u002Fp>\u003Cp>To make things easier and (almost) painless for you, I decided to share my experiences, mistakes I have made and how to avoid them with you! So let's get started.\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card kg-card-hascaption\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_programs_something_very_old.webp\" class=\"kg-image\" alt=\"an image depicting that programming with an old, not updated tech stack can be cumbersome\" loading=\"lazy\" width=\"1154\" height=\"647\" srcset=\"\u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_programs_something_very_old.webp 600w, \u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_programs_something_very_old.webp 1000w, \u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_programs_something_very_old.webp 1154w\" sizes=\"(min-width: 720px) 720px\">\u003Cfigcaption>\u003Cspan style=\"white-space: pre-wrap;\">Programming with an old, not updated tech stack can be cumbersome\u003C\u002Fspan>\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Ch2 id=\"why-even-upgrade\">Why even upgrade?\u003C\u002Fh2>\u003Cp>Well, Vue 2 has officially \u003Ca href=\"https:\u002F\u002Fv2.vuejs.org\u002Feol\u002F\" rel=\"noreferrer\">reached EOL on December 31st, 2023\u003C\u002Fa>. This means no more new features, updates or bug fixes. I therefore strongly advise you to migrate any project you would like to maintain and develop further.\u003C\u002Fp>\u003Ch2 id=\"existing-docs\">Existing docs\u003C\u002Fh2>\u003Cp>This guide is not the only guide that exists on how to migrate. The thing is, when I needed a guide on how to do it, it couldn't find any that would fit my needs. Most of the guides that exist try to be helpful, but they aren't.\u003C\u002Fp>\u003Cp>I have read things like:\u003C\u002Fp>\u003Col>\u003Cli> Update Vue 2.x to Vue 3.x in the package.json file, remove all Vue 2.x specific packages (template compiler, CLI plugins etc.)\u003C\u002Fli>\u003Cli>Install all new packages from the package.json file\u003C\u002Fli>\u003Cli>Fix the errors\u003C\u002Fli>\u003Cli>Fix the warnings\u003C\u002Fli>\u003Cli>You are ready to go!\u003C\u002Fli>\u003C\u002Fol>\u003Cp>When I read this \"helpful\" tips the first time, I was annoyed and thought: \"Well, maybe there are other guides helping me out with upgrading Vue and Vuetify\", so I opened another guide, and yet another guide etc. After reading five guides that provided me with nothing new, I gave up and decided to do it my way.\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_being_happy_that_his_things_work.webp\" class=\"kg-image\" alt=\"a programmer being happy, that his updating approach works as intended\" loading=\"lazy\" width=\"1154\" height=\"647\" srcset=\"\u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_being_happy_that_his_things_work.webp 600w, \u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_being_happy_that_his_things_work.webp 1000w, \u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_being_happy_that_his_things_work.webp 1154w\" sizes=\"(min-width: 720px) 720px\">\u003C\u002Ffigure>\u003Ch2 id=\"my-approach-to-updating-vue-26-to-vue-3x-including-vuetify\">My approach to updating Vue 2.6 to Vue 3.x (including Vuetify)\u003C\u002Fh2>\u003Cp>There are a few things to consider, before starting to update your app. Things that I thought about before updating included the following:\u003C\u002Fp>\u003Col>\u003Cli>How many packages do I have? Are there newer versions available that are compatible with Vue 3 using the options API\u003C\u002Fli>\u003Cli>Do I need all packages that are currently installed\u003C\u002Fli>\u003Cli>Do I just want to update to the latest releases without changing the API style of Vue, or do I want to adapt to the Composition API\u003C\u002Fli>\u003C\u002Fol>\u003Cp>After answering those questions, I had an understanding of which components need to be completely adopted and which would just need some refurbishment. \u003C\u002Fp>\u003Cp>And then, the horrors of updating a year's old product to the latest technology began.\u003C\u002Fp>\u003Ch3 id=\"my-first-approach-spoiler-did-not-work\">My first approach (Spoiler: did not work)\u003C\u002Fh3>\u003Cp>I followed the exact guidelines, that are outlined in almost every guide:\u003C\u002Fp>\u003Col>\u003Cli>remove Vue2 and vue-template-compiler from package.json\u003C\u002Fli>\u003Cli>run \u003Cem>npm install vue, @vue\u002Fcompat, @vue\u002Fcompiler-sfc\u003C\u002Fem>\u003C\u002Fli>\u003Cli>update \u003Cem>vue-router and vuex\u003C\u002Fem> to the latest version\u003C\u002Fli>\u003Cli>extend the Webpack config in vue.config.ts so that the \u003Cem>@vue\u002Fcompat\u003C\u002Fem> compiler is being used as alias for Vue\u003C\u002Fli>\u003Cli>change the main.js (in my case main.ts) file to use the new syntax to initialize the Vue application\u003C\u002Fli>\u003Cli>fix the errors\u003C\u002Fli>\u003Cli>fix the warnings\u003C\u002Fli>\u003C\u002Fol>\u003Cp>Even after following those guides step for step, I couldn't get the application to run.  At some point I realized that those guides were made for small projects, almost no external dependencies, no Typescript, no Vuetify etc. But that was not really what I was looking for...\u003C\u002Fp>\u003Cp>After trying several times, it was time for me to try something new.\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_has_an_innovative_idea-1.webp\" class=\"kg-image\" alt=\"a programmer looking at many screens\" loading=\"lazy\" width=\"1154\" height=\"647\" srcset=\"\u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_has_an_innovative_idea-1.webp 600w, \u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_has_an_innovative_idea-1.webp 1000w, \u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_programmer_that_has_an_innovative_idea-1.webp 1154w\" sizes=\"(min-width: 720px) 720px\">\u003C\u002Ffigure>\u003Ch3 id=\"my-second-approach\">My second approach\u003C\u002Fh3>\u003Cp>After reading through \u003Ca href=\"https:\u002F\u002Fv3-migration.vuejs.org\u002F\" rel=\"noreferrer\">this official migration \u003C\u002Fa>guide, I had an idea! It might be a brutal and direct approach to updating, but what could go wrong? The other approaches don't really work anyway for me, so I had nothing to lose.\u003C\u002Fp>\u003Cp>First, I followed \u003Ca href=\"https:\u002F\u002Fwww.sitepoint.com\u002Fwebpack-vite-migration\u002F\" rel=\"noreferrer\">the migration guide from Webpack to Vite\u003C\u002Fa>.  Of course, I adopted it to suit my needs for Vue 3, Vuetify and Typescript 5. Which basically means removing everything that has \u003Cem>@vue\u002Fcli \u003C\u002Fem>before its name and deleting all \u003Cem>babel\u003C\u002Fem> packages. After updating to Vite (in theory, I couldn't run the project at this point as everything else was deprecated basically). I could begin updating my dependencies.\u003C\u002Fp>\u003Cp>To update my packages, I used an extremely helpful tool called \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fnpm-check-updates\" rel=\"noreferrer\">NPM Check Updates\u003C\u002Fa>. After installing the package globally, you can just write \u003Cem>ncu -u \u003C\u002Fem>in the project directory, and it automatically updates all your dependencies to the latest versions. In my case, there were quite some major version jumps that needed to be installed.\u003C\u002Fp>\u003Cp>To make things easier for me, I decided to install \u003Cem>typescript-eslint\u003C\u002Fem>, the package provided me with very good linting for Typescript 5 and helped me fix compile errors even before they occurred. Furthermore, I decided to not change all option APIs to composition APIs, because the budget for the update was limited, and I didn't want to lose too much time.\u003C\u002Fp>\u003Cp>After preparing my package.json I could begin looking for problems. Oh boy, there were many of them!\u003C\u002Fp>\u003Ch4 id=\"detecting-the-obvious-issues\">Detecting the obvious issues\u003C\u002Fh4>\u003Cp>Obviously, as we now use Vue 3, we must change the way it is initialized. Previously this would be the recommended way:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-js\">new Vue({}).$mount('#app');\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>After updating to Vue 3 this now looks like this:\u003C\u002Fp>\u003Cpre>\u003Ccode>const app = createApp(App);\napp.mount('#app');\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The good thing when using the new syntax for the plugins is, that Vue directly tells you how fucked up your codebase is, and you can really just fix plugin after plugin.\u003C\u002Fp>\u003Ch5 id=\"fixing-the-plugins\">\u003Cstrong>Fixing the plugins\u003C\u002Fstrong>\u003C\u002Fh5>\u003Cp>Fixing the plugins was compared to the rest that followed relatively easy and straightforward. I decided to \u003Ca href=\"https:\u002F\u002Fvuetifyjs.com\u002Fen\u002Fgetting-started\u002Fupgrade-guide\u002F\" rel=\"noreferrer\">fix Vuetify first\u003C\u002Fa>. After doing that, I went on fixing the internationalization. By using the package\u003Ca href=\"https:\u002F\u002Fvue-i18n.intlify.dev\u002F\" rel=\"noreferrer\"> vue-i18n\u003C\u002Fa>, I was able to change as little code as possible, as this package still supports the old \u003Cem>$t()\u003C\u002Fem> syntax.\u003C\u002Fp>\u003Ch5 id=\"vue-i18n\">\u003Cstrong>vue-i18n\u003C\u002Fstrong>\u003C\u002Fh5>\u003Cpre>\u003Ccode>import { createI18n } from 'vue-i18n'\n\nimport { en } from '@\u002Flocales\u002Fen';\nimport { de } from '@\u002Flocales\u002Fde';\nimport { it } from '@\u002Flocales\u002Fit';\n\nconst messages = {\n  en,\n  de,\n  it\n}\n\nconst instance = createI18n({\n  locale: process.env.VUE_APP_I18N_LOCALE || 'de',\n  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'de',\n  messages,\n  globalInjection: true,\n  allowComposition: true,\n})\n\nexport function setLocale(lang: string) {\n  if (lang !== 'de' &amp;&amp; lang !== 'en' &amp;&amp; lang !== 'it') return;\n  instance.global.locale.value = lang;\n}\n\nexport function getLocale() {\n  return instance.global.locale;\n}\n\nexport default instance;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>After fixing i18n, I decided to implement the newer \u003Cem>this.t\u003C\u002Fem> syntax, just because it looked better and no need to configure Typescript. Basically in every component that used internationalization I just inserted:\u003C\u002Fp>\u003Cpre>\u003Ccode>setup() {\n    const { t } = useI18n()\n    return { t }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>By following this syntax, I was able to just use STRG+F for search in each component file and replace each occurrence of \u003Cem>$t(\u003C\u002Fem> with \u003Cem>t(. \u003C\u002Fem>Et voilà: Internalization for your application is fixed.\u003C\u002Fp>\u003Ch5 id=\"vuex\">\u003Cstrong>vuex\u003C\u002Fstrong>\u003C\u002Fh5>\u003Cp>After fixing Vuetify and i18n, I began to correctly initialize Vuex. This was as easy as could be!\u003C\u002Fp>\u003Cp>\u003Cstrong>The old (broken) way:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cpre>\u003Ccode>onst store = new Vuex.Store({\n  modules: {\n    authStore,\n    userStore,\n    companyStore,\n    vehicleStore,\n    vehicleManufacturerStore,\n    companyVehicleStore,\n    reportStore,\n    certificationAuthorityStore,\n    certificateStore,\n    certificateTemplateStore,\n  },\n})\n\nexport default store\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>The new (working) way:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cpre>\u003Ccode>const store = createStore({\n  modules: {\n    authStore,\n    userStore,\n    companyStore,\n    vehicleStore,\n    vehicleManufacturerStore,\n    companyVehicleStore,\n    reportStore,\n    certificationAuthorityStore,\n    certificateStore,\n    certificateTemplateStore,\n  },\n})\n\nexport default store\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Done. Vuex stores are now working again.\u003C\u002Fp>\u003Ch5 id=\"vue-router\">\u003Cstrong>vue-router\u003C\u002Fstrong>\u003C\u002Fh5>\u003Cp>After moving the router file to its own directory \"router\" and renaming it to \"index.ts\", updating was quite easy:\u003C\u002Fp>\u003Cp>Change this:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>const router = new Router({\n    mode: 'history',\n    routes: [{}],\n    base: 'BASE_URL'\n})\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>to this:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>const router = createRouter({\n    history: createWebHistory(),\n    routes: [{}]\n});\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>That's it, so routing works as well.\u003C\u002Fp>\u003Cp>By now, we have fixed several core dependencies, that have been the backbone of the application I need to upgrade:\u003C\u002Fp>\u003Col>\u003Cli>Vuetify\u003C\u002Fli>\u003Cli>Internationalization via vue-i18n\u003C\u002Fli>\u003Cli>Stores via Vuex\u003C\u002Fli>\u003Cli>Routing via vue-router\u003C\u002Fli>\u003C\u002Fol>\u003Cp>To continue this journey as painlessly as it has been so far, I decided to update the toast dependency that my project used to a package that supports the old syntax, so that I wouldn't have to change every single instantiation of toasts.\u003C\u002Fp>\u003Ch5 id=\"vue-toast-notification\">\u003Cstrong>vue-toast-notification\u003C\u002Fstrong>\u003C\u002Fh5>\u003Cp>I decided to use the package \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fvue-toast-notification?activeTab=readme\" rel=\"noreferrer\">vue-toast-notification\u003C\u002Fa>. It worked out of the box, nothing to configure whatsoever, I didn't even have to change any function calls and suddenly had working toasts again.\u003C\u002Fp>\u003Cp>Before I finally decided to use vue-toast-notification, I struggled to find a way to make the package \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fvuetify-toast-snackbar\" rel=\"noreferrer\">\u003Cstrong>vuetify-toast-snackbar\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>work again, which was used in the Vue 2 version of the project, but this project hasn't been updated for five years, so it was time to move on. As the new package vue-toast-notification provided me with the exact same functionalities and even extended the existent ones, it was the perfect fit for my needs.\u003C\u002Fp>\u003Cp>To use dialog confirms (as they have been previously implemented and really liked by our customer) I decided to follow the same approach as with toasts and installed the package \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fwobsoriano\u002Fvuetify-use-dialog\" rel=\"noreferrer\">vuetify-use-dialog\u003C\u002Fa> as a replacement for \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fvuetify-confirm\" rel=\"noreferrer\">vuetify-confirm\u003C\u002Fa>. Same thing here, nothing to change, worked just fine as before.\u003C\u002Fp>\u003Cp>The big advantage of both packages (vuetify-use-dialog and vuetify-toast-notification) was, that altough I had nothing to change in the code base (except the instantiation in the 'main.ts' file), they worked better than the old ones, looked better and had more customization options.\u003C\u002Fp>\u003Ch5 id=\"vee-validate\">\u003Cstrong>vee-validate\u003C\u002Fstrong>\u003C\u002Fh5>\u003Cp>I completely threw out \u003Ca href=\"https:\u002F\u002Fvee-validate.logaretm.com\u002Fv4\u002F\" rel=\"noreferrer\">vee-validate\u003C\u002Fa> because I didn't see any added value for my use cases that Vuetify didn't provide out of the box. I really only had to validate simple things, such as unique emails, required fields etc. Some API calls, but mostly just standard regex, and Vuetify can validate pretty well (even asynchronous validation) without having to implement and install a new package like vee-validate. So I decided it would be the easiest approach to just use the already defined rules and use them with Vuetify instead of vee-validate. Examples of the rules I used that worked just fine:\u003C\u002Fp>\u003Cpre>\u003Ccode>import i18n from '@\u002Fi18n'\nimport { regexEUNumber, regexNumbersAndSpecialChars } from '.\u002Fhelpers'\nimport userService from '.\u002Fservices\u002FuserService'\n\nconst { t } = i18n.global\n\nexport const requiredRule = (value: any) =&gt; {\n  \u002F\u002F CODE\n}\n\nexport const decimalRule = (value: any) =&gt; {\n  \u002F\u002F CODE\n}\n\nexport const checkUserNameRule = async (value: any) =&gt; {\n  \u002F\u002F CODE\n}\n\nexport const checkEmailRule = async (value: any, oldValue: any) =&gt; {\n  \u002F\u002F CODE\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>You see that even asynchronous calls can be made without any problem. To use those rules in my Vue components, I needed to change the following things:\u003C\u002Fp>\u003Col>\u003Cli>Delete all &lt;validation-observer&gt; tags, as they were deprecated by vee-validate already, and I wouldn't even use this package anymore\u003C\u002Fli>\u003Cli>Replace the observer with the following code snipet for each input:\u003C\u002Fli>\u003C\u002Fol>\u003Cpre>\u003Ccode>&lt;v-text-field\n      v-model=\"certificationAuthority.email\"\n      color=\"secondary\"\n      :label=\"t('email') + '*'\"\n      prepend-icon=\"mdi-email\"\n      validate-on-blur\n      variant=\"underlined\"\n      :rules=\"[email]\"\n\u002F&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>and the rules were imported in the setup:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>setup() {\n    const { t } = useI18n()\n    const required = (value: any) =&gt; requiredRule(value)\n    const email = (value: any) =&gt; emailRule(value)\n    return { t, required, email }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Col start=\"3\">\u003Cli>remove all \u003Cem>:error-message\u003C\u002Fem> properties from the inputs, as they are not needed anymore because Vuetify handles everything just fine\u003C\u002Fli>\u003Cli>Wrap each input in a \u003Cem>v-form\u003C\u002Fem> with a v-model so that you can check whether the form is valid or not:\u003C\u002Fli>\u003C\u002Fol>\u003Cpre>\u003Ccode>&lt;v-form v-model=\"validCertificationAuthorityContact\" validate-on-blur&gt;\n    &lt;v-text-field\n      v-model=\"certificationAuthority.email\"\n      color=\"secondary\"\n      :label=\"t('email') + '*'\"\n      prepend-icon=\"mdi-email\"\n      validate-on-blur\n      variant=\"underlined\"\n      :rules=\"[email]\"\n    \u002F&gt;\n&lt;\u002Fv-form&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Col start=\"5\">\u003Cli>in the saving function, just check if the variable is truthy. Et voilà: Working validation without any third party library.\u003C\u002Fli>\u003C\u002Fol>\u003Ch4 id=\"detecting-the-not-so-obvious-issues\">Detecting the not so obvious issues\u003C\u002Fh4>\u003Cp>Excited to see the project with the newly updated dependencies, I was quite disappointed, when I saw that no data-table showed anything. But the issue was found quickly:\u003C\u002Fp>\u003Cp>Vuetify data tables changed the way they are handling their data, previously the text and the value of each item was accessed via:\u003C\u002Fp>\u003Cpre>\u003Ccode>headers(): any {\n    return [\n        {\n            text: 'TEXT',\n            value: 'KEY'\n        },\n    ]\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>this changed to:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>headers(): any {\n    return [\n        {\n            title: 'TEXT',\n            key: 'KEY'\n        },\n    ]\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>And suddenly, data was in my tables. \u003C\u002Fp>\u003Cp>Other issues, that were more or less obvious, were for example deprecated properties on &lt;v-btn&gt; components, or deprecated properties and tags in general. But by now your application should be running Vite, so you can just click through and look for things that aren't quite right. In my case, it was mainly formatting and layouts that were not created correctly.\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fvue-2-to-vue-3-a-nearly-painless-approach-seadev_studios_a_happy_programmer_that_successfully_deployed.webp\" class=\"kg-image\" alt=\"a happy programmer, because everything just worked out\" loading=\"lazy\" width=\"550\" height=\"308\">\u003C\u002Ffigure>\u003Cp>I really hope that this guide helped you to migrate Vue 2 to Vue 3! If you have any questions or feedback, feel free to leave a comment. Thank you for reading!\u003C\u002Fp>\u003Cp>For more blogs like this, feel free to sign up:\u003C\u002Fp>\u003Cdiv class=\"kg-card kg-signup-card kg-width-wide \" data-lexical-signup-form=\"\" style=\"background-color: #F0F0F0; display: none;\">\n            \n            \u003Cdiv class=\"kg-signup-card-content\">\n                \n                \u003Cdiv class=\"kg-signup-card-text \">\n                    \u003Ch2 class=\"kg-signup-card-heading\" style=\"color: #000000;\">\u003Cspan style=\"white-space: pre-wrap;\">Sign up for SEADEV Studios Blog\u003C\u002Fspan>\u003C\u002Fh2>\n                    \u003Cp class=\"kg-signup-card-subheading\" style=\"color: #000000;\">\u003Cspan style=\"white-space: pre-wrap;\">News, Updates, Learnings &amp; Insights\u003C\u002Fspan>\u003C\u002Fp>\n                    \n        \u003Cform class=\"kg-signup-card-form\" data-members-form=\"signup\">\n            \n            \u003Cdiv class=\"kg-signup-card-fields\">\n                \u003Cinput class=\"kg-signup-card-input\" id=\"email\" data-members-email=\"\" type=\"email\" required=\"true\" placeholder=\"Your email\">\n                \u003Cbutton class=\"kg-signup-card-button kg-style-accent\" style=\"color: #FFFFFF;\" type=\"submit\">\n                    \u003Cspan class=\"kg-signup-card-button-default\">Subscribe\u003C\u002Fspan>\n                    \u003Cspan class=\"kg-signup-card-button-loading\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" height=\"24\" width=\"24\" viewBox=\"0 0 24 24\">\n        \u003Cg stroke-linecap=\"round\" stroke-width=\"2\" fill=\"currentColor\" stroke=\"none\" stroke-linejoin=\"round\" class=\"nc-icon-wrapper\">\n            \u003Cg class=\"nc-loop-dots-4-24-icon-o\">\n                \u003Ccircle cx=\"4\" cy=\"12\" r=\"3\">\u003C\u002Fcircle>\n                \u003Ccircle cx=\"12\" cy=\"12\" r=\"3\">\u003C\u002Fcircle>\n                \u003Ccircle cx=\"20\" cy=\"12\" r=\"3\">\u003C\u002Fcircle>\n            \u003C\u002Fg>\n            \u003Cstyle data-cap=\"butt\">\n                .nc-loop-dots-4-24-icon-o{--animation-duration:0.8s}\n                .nc-loop-dots-4-24-icon-o *{opacity:.4;transform:scale(.75);animation:nc-loop-dots-4-anim var(--animation-duration) infinite}\n                .nc-loop-dots-4-24-icon-o :nth-child(1){transform-origin:4px 12px;animation-delay:-.3s;animation-delay:calc(var(--animation-duration)\u002F-2.666)}\n                .nc-loop-dots-4-24-icon-o :nth-child(2){transform-origin:12px 12px;animation-delay:-.15s;animation-delay:calc(var(--animation-duration)\u002F-5.333)}\n                .nc-loop-dots-4-24-icon-o :nth-child(3){transform-origin:20px 12px}\n                @keyframes nc-loop-dots-4-anim{0%,100%{opacity:.4;transform:scale(.75)}50%{opacity:1;transform:scale(1)}}\n            \u003C\u002Fstyle>\n        \u003C\u002Fg>\n    \u003C\u002Fsvg>\u003C\u002Fspan>\n                \u003C\u002Fbutton>\n            \u003C\u002Fdiv>\n            \u003Cdiv class=\"kg-signup-card-success\" style=\"color: #000000;\">\n                Email sent! Check your inbox to complete your signup.\n            \u003C\u002Fdiv>\n            \u003Cdiv class=\"kg-signup-card-error\" style=\"color: #000000;\" data-members-error=\"\">\u003C\u002Fdiv>\n        \u003C\u002Fform>\n        \n                    \u003Cp class=\"kg-signup-card-disclaimer\" style=\"color: #000000;\">\u003Cspan style=\"white-space: pre-wrap;\">No spam. Unsubscribe anytime.\u003C\u002Fspan>\u003C\u002Fp>\n                \u003C\u002Fdiv>\n            \u003C\u002Fdiv>\n        \u003C\u002Fdiv>"]