<?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: Sergio Dinis Lopes</title>
    <description>The latest articles on DEV Community by Sergio Dinis Lopes (@sergiodinislopes).</description>
    <link>https://dev.to/sergiodinislopes</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%2F3855789%2Ff5a923c8-a689-47e4-b650-621152e15c5b.png</url>
      <title>DEV Community: Sergio Dinis Lopes</title>
      <link>https://dev.to/sergiodinislopes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sergiodinislopes"/>
    <language>en</language>
    <item>
      <title>I* rewrote my jQuery autocomplete plugin as a zero-dependency ES6 library (with Vue, React &amp; Svelte adapters)</title>
      <dc:creator>Sergio Dinis Lopes</dc:creator>
      <pubDate>Wed, 01 Apr 2026 14:50:44 +0000</pubDate>
      <link>https://dev.to/sergiodinislopes/i-rewrote-my-jquery-autocomplete-plugin-as-a-zero-dependency-es6-library-with-vue-react-svelte-lj</link>
      <guid>https://dev.to/sergiodinislopes/i-rewrote-my-jquery-autocomplete-plugin-as-a-zero-dependency-es6-library-with-vue-react-svelte-lj</guid>
      <description>&lt;p&gt;Back in 2016, I published &lt;a href="https://github.com/sergiodlopes/jquery-flexdatalist" rel="noopener noreferrer"&gt;Flexdatalist&lt;/a&gt; — a jQuery plugin for autocomplete/datalist inputs. It quietly grew to &lt;strong&gt;364 stars&lt;/strong&gt; and &lt;strong&gt;81 forks&lt;/strong&gt; on GitHub, people, myself included, have been using it in production ever since.&lt;/p&gt;

&lt;p&gt;But jQuery in 2026? It was time for a rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;The original plugin did a lot: remote and static data, multiple tags, result grouping, keyboard navigation, localStorage caching. It worked well, but it was ~2000 lines of jQuery spaghetti that I wrote when I was a less experienced developer. Every time someone opened an issue, I'd wince looking at the code.&lt;/p&gt;

&lt;p&gt;The rewrite had been on my mental backlog for years. I kept postponing it because the scope felt overwhelming — rewriting that much logic while preserving backward compatibility, keeping the same CSS class names, supporting the same &lt;code&gt;data-*&lt;/code&gt; attribute API, and not breaking things for existing users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Claude Code
&lt;/h2&gt;

&lt;p&gt;I decided to try using &lt;a href="https://www.anthropic.com/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; (Anthropic's AI coding agent) as a pair-programming partner for the rewrite. Not to generate the whole thing blindly — but to work through it methodically.&lt;/p&gt;

&lt;p&gt;Here's how the collaboration actually worked:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I drove the architecture.&lt;/strong&gt; I decided on the class structure, the public API shape, how events should work (native &lt;code&gt;CustomEvent&lt;/code&gt; instead of jQuery's event system), and which features to keep, drop, or improve. Made sure the code was well documented for future maintenance (agentic or not).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude handled the heavy lifting.&lt;/strong&gt; Converting jQuery DOM manipulation to vanilla JS, rewriting the search/filtering logic, building the tag management system, implementing the localStorage cache with TTL and garbage collection. The kind of work that's tedious but well-defined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The framework adapters were the real win.&lt;/strong&gt; Once the core was solid, I asked Claude to create Vue, React, and Svelte wrappers. Each one is a thin adapter (~5 kB) that maps the core's imperative API to the framework's declarative model — props, events, refs, &lt;code&gt;v-model&lt;/code&gt;/&lt;code&gt;bind:value&lt;/code&gt;. Writing idiomatic components for three frameworks I don't use daily would have taken me days. It took an afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The docs and examples too.&lt;/strong&gt; The interactive &lt;a href="http://projects.sergiodinislopes.pt/flexdatalist/examples.html" rel="noopener noreferrer"&gt;examples page&lt;/a&gt; with 30+ live demos, the &lt;a href="http://projects.sergiodinislopes.pt/flexdatalist/" rel="noopener noreferrer"&gt;documentation page&lt;/a&gt; with the full options/API/events reference — all built collaboratively.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in v3
&lt;/h2&gt;

&lt;p&gt;The core is now a single ES6 class (~2300 lines), zero dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Flexdatalist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#city&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/cities&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;searchIn&lt;/span&gt;&lt;span class="p"&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;name&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;zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;valueProperty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;textProperty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{name}, {zip}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;minLength&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="c1"&gt;// Chainable API&lt;/span&gt;
&lt;span class="nx"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;42&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="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;select:flexdatalist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What's new
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No jQuery&lt;/strong&gt; — uses native &lt;code&gt;fetch()&lt;/code&gt;, &lt;code&gt;CustomEvent&lt;/code&gt;, &lt;code&gt;classList&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async-ready&lt;/strong&gt; — &lt;code&gt;init()&lt;/code&gt; returns a Promise that resolves after data loading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chainable API&lt;/strong&gt; — &lt;code&gt;setValue()&lt;/code&gt;, &lt;code&gt;addValue()&lt;/code&gt;, &lt;code&gt;removeValue()&lt;/code&gt;, &lt;code&gt;clear()&lt;/code&gt;, &lt;code&gt;disable()&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS custom properties&lt;/strong&gt; — theme with &lt;code&gt;--fdl-accent&lt;/code&gt;, &lt;code&gt;--fdl-tag-bg&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework adapters&lt;/strong&gt; — first-class Vue, React, and Svelte components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark mode&lt;/strong&gt; support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;getText()&lt;/code&gt;&lt;/strong&gt; — get the display text separately from the stored value&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;searchEqual&lt;/code&gt;&lt;/strong&gt; — exact match mode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;showAddNewItem&lt;/code&gt;&lt;/strong&gt; — "Add new" option when no results match&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;collapseAfterN&lt;/code&gt;&lt;/strong&gt; — collapse tags after N items&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monorepo&lt;/strong&gt; — pnpm workspaces with &lt;code&gt;packages/core&lt;/code&gt;, &lt;code&gt;packages/vue&lt;/code&gt;, &lt;code&gt;packages/react&lt;/code&gt;, &lt;code&gt;packages/svelte&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What stayed the same
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same CSS class names&lt;/strong&gt; — swap the JS file and your styles still work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same &lt;code&gt;data-*&lt;/code&gt; attributes&lt;/strong&gt; — &lt;code&gt;data-url&lt;/code&gt;, &lt;code&gt;data-search-in&lt;/code&gt;, &lt;code&gt;data-min-length&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same event names&lt;/strong&gt; — &lt;code&gt;change:flexdatalist&lt;/code&gt;, &lt;code&gt;select:flexdatalist&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-discovery&lt;/strong&gt; — &lt;code&gt;&amp;lt;input class="flexdatalist"&amp;gt;&lt;/code&gt; still initialises automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Migration is mostly mechanical: replace &lt;code&gt;$('#el').flexdatalist(opts)&lt;/code&gt; with &lt;code&gt;Flexdatalist.init('#el', opts)&lt;/code&gt; and change event handlers from jQuery's extra args to &lt;code&gt;e.detail&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework adapters
&lt;/h2&gt;

&lt;p&gt;Each adapter wraps the core and exposes a native component API:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vue 3:&lt;/strong&gt;&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;Flexdatalist&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"/api/cities"&lt;/span&gt; &lt;span class="na"&gt;:min-length=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"(item) =&amp;gt; console.log(item)"&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;&lt;strong&gt;React:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Flexdatalist&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/api/cities"&lt;/span&gt; &lt;span class="na"&gt;minLength&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;onSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Svelte:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Flexdatalist&lt;/span&gt; &lt;span class="na"&gt;bind:value=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"/api/cities"&lt;/span&gt; &lt;span class="na"&gt;minLength=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;on:select=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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;All options are available as props. All events are re-emitted as framework-native events. Instance methods are exposed via refs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest thoughts on AI-assisted development
&lt;/h2&gt;

&lt;p&gt;Using Claude Code wasn't a magic "write my project" button. Here's what worked and what didn't:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Worked great for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Translating jQuery patterns to vanilla JS (well-defined, mechanical)&lt;/li&gt;
&lt;li&gt;Scaffolding framework adapters (repetitive but needs framework-specific knowledge)&lt;/li&gt;
&lt;li&gt;Writing documentation and examples&lt;/li&gt;
&lt;li&gt;Catching edge cases I'd have missed (event cleanup on destroy, dialog positioning, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Still needed me for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture decisions (API design, what to expose, what to keep internal)&lt;/li&gt;
&lt;li&gt;Knowing what the library &lt;em&gt;should&lt;/em&gt; do (domain knowledge from 10 years of user feedback)&lt;/li&gt;
&lt;li&gt;Final QA and testing with real data on a app I'm developing&lt;/li&gt;
&lt;li&gt;Deciding when something was "good enough" vs. over-engineered&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest summary: it turned a project I'd been postponing for years into something I finished in a few weeks. Not because the AI wrote everything — but because it handled the parts that were blocking me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&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;flexdatalist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sergiodlopes/flexdatalist" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://projects.sergiodinislopes.pt/flexdatalist/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://projects.sergiodinislopes.pt/flexdatalist/examples.html" rel="noopener noreferrer"&gt;Live Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/flexdatalist" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Framework adapters: &lt;a href="https://www.npmjs.com/package/flexdatalist-vue" rel="noopener noreferrer"&gt;&lt;code&gt;flexdatalist-vue&lt;/code&gt;&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/flexdatalist-react" rel="noopener noreferrer"&gt;&lt;code&gt;flexdatalist-react&lt;/code&gt;&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/flexdatalist-svelte" rel="noopener noreferrer"&gt;&lt;code&gt;flexdatalist-svelte&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope the little lib is as helpful to you as it was for me all these years. Happy to answer questions in the comments.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
