I'm a frontend developer with about three years of experience. Until a few months ago, "publish an npm package" lived on my someday list — the kind of thing you assume requires a deeper relationship with build tooling than you actually have. Then I built one. It's called daterly, it's a React date picker, and it's already running in internal projects at the company I work for.
The twist: I wrote most of it with AI — specifically Claude Code and the wider Claude toolset. This is the honest version of how that went. Not "AI built my startup overnight," but a real account of where the AI carried me, where it slowed me down, and what I'd actually keep from the experience.
Why build another date picker
The internet does not need another React date picker. I know. But we needed this one.
At work (sima-land) we lean on react-hook-form everywhere. It's the backbone of how we handle forms across projects. The date picker we were using — react-datepicker — kept getting in the way of that. Two things drove us up the wall:
- Styling was a fight. Overriding its look to match our design system always felt like wrestling specificity rather than setting a few variables.
- The react-hook-form integration was awkward. Wiring it into RHF cleanly took more glue code than it should have, every single time.
When the same papercut shows up in project after project, it stops being a papercut. We use one tech stack on purpose — a shared, repeatable way of building things so any of us can move between projects without relearning the basics. A date picker that fought both our styling approach and our form library was a crack in that consistency.
So the real motivation wasn't "wouldn't it be cool to publish a package." It was: we want one tool that speaks our stack fluently. First-class RHF support, styling that bends without a struggle, and the locale/format behavior we actually need (Russian market: ru locale, dd.MM.yyyy by default). That's the takeaway I keep coming back to — the package exists to protect a way of working, not to chase npm downloads.
What it ended up being
daterly is built on react-day-picker v9 (headless) and date-fns v4. The headline features:
- Single date and range picking, controlled or uncontrolled
- A masked text input so people can type a date instead of only clicking a calendar
-
Arbitrary locales and formats via props — the input mask regenerates itself from the
dateFormatyou pass - Optional time selection
-
Zero-overhead react-hook-form integration via a separate
daterly/rhfentry point — if you don't use RHF, you don't pay for it - Styling through
--daterly-*CSS variables anddata-*state attributes, so you can theme it without touching JavaScript
The RHF wrappers are generic over your form's value type, so name gets autocomplete and type-safety:
import { RHFDatePicker } from 'daterly/rhf';
<RHFDatePicker<BookingFormValues>
name="checkIn"
label="Check-in date"
rules={{ validate: (v) => v !== undefined || 'Pick a date' }}
/>
That snippet is the whole reason the project exists, honestly.
Building it with AI: the good parts
I worked almost entirely inside Claude Code, with Claude Design for the visual side. The parts where the AI genuinely shone were the fiddly, self-contained algorithms — the stuff that's annoying to write by hand but easy to specify.
The input mask is the best example. We implemented our own digit-only mask instead of pulling in a masking library, and there's real subtlety in it:
- Rebuild the masked string from raw digits on every keystroke.
- Restore the cursor position with
requestAnimationFrameafter React re-renders the input — otherwise the caret jumps to the end and typing feels broken. - Skip over separators when you press Backspace on one.
- Strip non-digits on paste before masking.
- Validate via a round-trip check:
format(parse(masked)) === masked. That elegantly catches things like32.01.2024— it parses, but it doesn't format back to the same string, so you know it's invalid.
That round-trip trick is the kind of thing the AI proposed that made me go "oh, that's nice." Describing the edge cases in plain language and getting a working first pass back was a real accelerator. Same with boilerplate-heavy work: dual ESM/CJS build config, TypeScript declaration setup, test scaffolding. Tedious to set up from scratch, quick to generate and then review.

Building it with AI: the not-so-good parts
It wasn't magic, and pretending otherwise would be dishonest.
The limits and the lag. I was on the Pro plan, and I hit usage limits more than once mid-flow — exactly when you've built momentum and don't want to stop. On top of that, it noticeably slowed down on a larger context, which broke the rhythm. If you're going to lean on AI for a real project, budget for the friction of waiting and rationing, not just the writing.
It needs a driver, not a passenger. The AI is great at producing a plausible chunk of code. Whether that chunk is correct, fits the existing patterns, and doesn't quietly reinvent something three files over — that's still on me. The most valuable skill wasn't prompting; it was reading every diff like a code reviewer who doesn't trust the author. A junior who can't evaluate the output would have shipped subtly broken behavior here.

From "it works on my machine" to an actual package
This is the part I underestimated, and the part I'm most glad I didn't skip. Going from a working component to something installable and maintainable is a whole second project:
- Dual ESM + CJS output with proper type declarations, built via tsup.
- Versioning with Changesets, so every change is intentional and the changelog writes itself.
-
CI, code coverage, and a bundle-size budget (
size-limit) so the thing doesn't quietly balloon. - Component tests with Playwright and Vitest — a masked input has enough edge cases that you really want them locked down.
None of this is glamorous, but it's the difference between a gist and a package other people can depend on.

The 0.4.0 incident
A small, very human lesson. Early on, I ran the Changesets CLI interactively and — distracted — picked minor instead of patch. The version jumped to 0.4.0 instead of 0.3.1. No undo on a published version; you just live with the gap.
The fix was a process change I now recommend to anyone: don't bump versions interactively. I have it written into the project's instructions for the AI too — create the changeset file by hand, decide the bump deliberately (patch for fixes, minor for new backwards-compatible props, major for breaking changes), and only then publish. A thirty-second mistake taught me more about release discipline than any tutorial.

What I'd actually take away
If you're a frontend dev sitting where I was, three things:
- Build for your stack, not for the stars. The best reason to make a library is that it removes friction you hit every day. daterly's whole job is to make our standard stack — react-hook-form, our styling approach, our locale defaults — feel native. The npm badge is a side effect.
- AI compresses the boring parts, not the judgment. It wrote a lot of correct code fast. It also needed me to catch what it got wrong, ration limited usage, and wait out the slow moments. Treat it as a fast junior pair, not an autopilot.
- The packaging is the real work. The component took days. The build config, versioning, CI, tests, and docs took longer — and that's what makes it usable by anyone other than me.
daterly is MIT-licensed and on npm. Code and docs are on GitHub. If you're fighting your date picker's styling or RHF integration, give it a look — and if you build your own thing instead, even better. That's the point.
I'm also open to freelance work and collaboration. If you've got something you're building and want a hand, or you just want to see what else I've made, it's all at artemy.tech.

Top comments (1)
This is a good reminder that AI speeds up implementation, not ownership. Generating the component is only part of the journey turning it into a production-ready package with tests, versioning, CI, documentation, and a stable API is where most of the engineering effort still goes. That's the difference between code that works once and software other teams can confidently depend on.