Back in 2016, I published Flexdatalist — a jQuery plugin for autocomplete/datalist inputs. It quietly grew to 364 stars and 81 forks on GitHub, people, myself included, have been using it in production ever since.
But jQuery in 2026? It was time for a rewrite.
The problem
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.
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 data-* attribute API, and not breaking things for existing users.
Enter Claude Code
I decided to try using Claude Code (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.
Here's how the collaboration actually worked:
I drove the architecture. I decided on the class structure, the public API shape, how events should work (native CustomEvent 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).
Claude handled the heavy lifting. 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.
The framework adapters were the real win. 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, v-model/bind:value. Writing idiomatic components for three frameworks I don't use daily would have taken me days. It took an afternoon.
The docs and examples too. The interactive examples page with 30+ live demos, the documentation page with the full options/API/events reference — all built collaboratively.
What changed in v3
The core is now a single ES6 class (~2300 lines), zero dependencies:
const [fd] = await Flexdatalist.init('#city', {
url: '/api/cities',
searchIn: ['name', 'zip'],
valueProperty: 'id',
textProperty: '{name}, {zip}',
minLength: 2,
});
// Chainable API
fd.setValue('42')
.on('select:flexdatalist', e => console.log(e.detail));
What's new
-
No jQuery — uses native
fetch(),CustomEvent,classList, etc. -
Async-ready —
init()returns a Promise that resolves after data loading -
Chainable API —
setValue(),addValue(),removeValue(),clear(),disable(), etc. -
CSS custom properties — theme with
--fdl-accent,--fdl-tag-bg, etc. - Framework adapters — first-class Vue, React, and Svelte components
- Dark mode support
-
getText()— get the display text separately from the stored value -
searchEqual— exact match mode -
showAddNewItem— "Add new" option when no results match -
collapseAfterN— collapse tags after N items -
Monorepo — pnpm workspaces with
packages/core,packages/vue,packages/react,packages/svelte
What stayed the same
- Same CSS class names — swap the JS file and your styles still work
-
Same
data-*attributes —data-url,data-search-in,data-min-length, etc. -
Same event names —
change:flexdatalist,select:flexdatalist, etc. -
Auto-discovery —
<input class="flexdatalist">still initialises automatically
Migration is mostly mechanical: replace $('#el').flexdatalist(opts) with Flexdatalist.init('#el', opts) and change event handlers from jQuery's extra args to e.detail.
Framework adapters
Each adapter wraps the core and exposes a native component API:
Vue 3:
<Flexdatalist v-model="city" url="/api/cities" :min-length="2"
@select="(item) => console.log(item)" />
React:
<Flexdatalist url="/api/cities" minLength={2}
onSelect={(item) => console.log(item)} />
Svelte:
<Flexdatalist bind:value={city} url="/api/cities" minLength={2}
on:select={(e) => console.log(e.detail)} />
All options are available as props. All events are re-emitted as framework-native events. Instance methods are exposed via refs.
Honest thoughts on AI-assisted development
Using Claude Code wasn't a magic "write my project" button. Here's what worked and what didn't:
Worked great for:
- Translating jQuery patterns to vanilla JS (well-defined, mechanical)
- Scaffolding framework adapters (repetitive but needs framework-specific knowledge)
- Writing documentation and examples
- Catching edge cases I'd have missed (event cleanup on destroy, dialog positioning, etc.)
Still needed me for:
- Architecture decisions (API design, what to expose, what to keep internal)
- Knowing what the library should do (domain knowledge from 10 years of user feedback)
- Final QA and testing with real data on a app I'm developing
- Deciding when something was "good enough" vs. over-engineered
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.
Try it
npm install flexdatalist
Framework adapters: flexdatalist-vue · flexdatalist-react · flexdatalist-svelte
Hope the little lib is as helpful to you as it was for me all these years. Happy to answer questions in the comments.
Top comments (0)