Skip to main content

The Floor Is React 18

· 5 min read
Alex Smith
Software Engineer

The Floor Is React 18, drawn as a pixel art lava level: tiles labeled 16 and 17 sink into the lava while the React atom hops between a solid brick floor labeled React 18 and a floating 19 platform

In June, bestax-bulma v4.0.0 dropped support for React 16 and 17. That's the whole release: one breaking change, no new components, and if you're on React 18 or 19 you won't feel a thing. Here's why I moved the floor anyway.

Same housekeeping as the v3 forms recap: this is a recap, not breaking news. v4.0.0 was tagged on June 20, 2026, three days after v3.0.0, the library sits at 5.8.0 today, and this is the third post in the catch-up series.

What Changed

Two lines in package.json. Honestly, that's it:

- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
- "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"

No components changed, no props were renamed, no CSS moved. The rest of the release was internal lint tooling that never ships to you. The 3.x to 4.x migration guide is the shortest one we have, and it exists mostly to say there's nothing to migrate.

Why I Dropped 16 and 17

The support claim wasn't real. CI built and tested this library against React 18 and 19. Nothing ever ran against 16 or 17, so the ^16.8.0 in the peer range was a claim, not a fact. I know exactly what untested claims are worth, because the day I added a React 18 + 19 test matrix, its very first run failed on React 18: a Carousel test helper passed ref through a prop spread, which only works on React 19's ref-as-prop. If React 18 could break quietly inside the range I actually test, what do you figure the odds were that React 16.8 still worked?

v3 had already crossed the line. The date and time pickers that headlined v3.0.0 call useId for SSR-safe accessible IDs, and useId doesn't exist before React 18. So v3 shipped claiming React 16.8 support while its newest components would have crashed there on mount. v4.0.0 didn't really drop 16 and 17; it stopped claiming something that had already stopped being true.

Old floors are expensive. Keeping 16 and 17 would have meant a fallback ID generator and shims for exactly the versions almost nobody runs. React 18 came out in March 2022, React 19 has been stable since December 2024, and React 16.8 is from February 2019. Every major in a peer range is a promise to test against it, reproduce bugs on it, and design APIs around its limits. I'd rather make a smaller promise and keep it.

The React 18 + 19 Matrix

Narrowing the range was half the move. The other half was making what's left verifiable: since that same day, every CI run includes a compatibility matrix that builds, type-checks, and tests the library once against React 18 and once against React 19, with real peer installs (no --legacy-peer-deps anywhere) and fail-fast off so a break on either major reports on its own. The peer range and the test matrix now say the same thing. ^18.0.0 || ^19.0.0 isn't a hope, it's what CI verified on the latest commit.

Upgrading

  • On React 18 or 19: skip 4.x and go straight to the current 5.x; that's the path forward. The React floor is identical, and the only breaking change past 4.x is the removal of one prefixed stylesheet variant you probably never imported (the 4.x to 5.x guide has the two-step swap if you did).
  • On React 16 or 17: stay on @allxsmith/bestax-bulma@^3 until your app can move to React 18, and mind that the v3 date and time pickers already assume a modern React.

The 3.x to 4.x migration guide covers both paths.

Sometimes You Gotta Move On

If you maintain a package, a wide peer range feels like generosity. It's also the easiest promise to make, because nothing enforces it: peer ranges aren't verified by your test suite unless you build that verification yourself, and the versions at the old end are exactly the ones your CI stopped seeing years ago. That's how support rots. Not in one decision, but in one hook you adopt, one helper you refactor, one API you design around, until the range describes a library that no longer exists.

So this is me saying the quiet part in a changelog font: I dropped React 16 and 17 because I couldn't keep the promise, and pretending is worse than a major bump. React 16.8 gave us hooks and changed how all of us write components, and 17 carried the whole ecosystem across a bridge. Genuinely: thanks. But sometimes you gotta move on.

What's Next

The catch-up series rolls on: next is v5.0.0, the release that made the CSS story one story, any prefix. The tracker has the full plan.

Meanwhile, the floor is holding.