• Switch back to microticks for scheduling as the default (#3911, thanks @marvinhagemeister , @JoviDeCroock)

Bug Fixes

  • Fix hydrating <textarea> with value prop (#3891, thanks @andrewiggins)
  • Prevent memory leak when creating and destroying root nodes by clearing currentComponent (#3908, thanks @JoviDeCroock)
  • Fix regression in 10.12.1 from #3889 which could lead to a state not updating after a context update was enqueued (#3906, thanks @JoviDeCroock)
  • Fix tests assertions for IE11 (#3912, thanks @marvinhagemeister)


  • Add indeterminate property (#3837, thanks @rschristian)
  • Add aria role attribute values (#3904, thanks @shoonia)
  • Add missing SVG Elements to types (#3905, thanks @shoonia)
  • Add Missing MemoExoticComponent type in preact/compat (#3898, thanks @rschristian)
  • Add ARIA attribute types (#3910, thanks @andrewiggins)

Bug Fixes

  • Fix non-numeric numbers passed to width or height attribute not working correctly (#3888, thanks @JoviDeCroock)
  • Fix createContext update being blocked by shouldComponentUpdate (#3889, thanks @marvinhagemeister)


  • Use microtick outside of events (#3879, thanks @JoviDeCroock)
  • Re-sort rerender queue if modified while we are processing rerenders (#3871, thanks @andrewiggins)
  • Preserve event handler return values (#3812, thanks @developit)

Bug Fixes

  • Fix: avoid bailing in strict equality (#3884, thanks @JoviDeCroock)
  • When unmounting, continue with the last DOM element's nextSibling (#3878, thanks @andrewiggins)
  • Fix parameters or JSX dev runtime (#3880, thanks @wooorm)
  • Improve Fragment unmounting while correctly swapping nested fragments (#3875, thanks @andrewiggins)
  • Clear css properties when passed undefined (#3862, thanks @andrewiggins)
  • Debug: limit "object as children" error to elements (#3801, thanks @developit)
  • Invoke setState callbacks setup in componentWillMount (#3806, thanks @andrewiggins)


  • add exactOptionalPropertyTypes support to html attributes (#3868, thanks @deadem)
  • Changes EventHandler<...> to have a this of type void. (#3867, thanks @MicahZoltu)
  • Narrows type of parent in render functions. (#3863, thanks @MicahZoltu)


  • Improve suspense test spies (#3856, thanks @andrewiggins)
  • docs: Fix a few typos (#3844, thanks @timgates42)
  • docs: Removes recommendation for preact-cli (#3816, thanks @rschristian)

Bug Fixes

  • Add an explicit default export for compatibility with esbuild (#3783, thanks @Verseth)
  • Fix useId uniqueness with shared parents + DOM nodes in between (#3773, thanks @marvinhagemeister)
  • Fix case where keyed children would get removed (#3779, thanks @JoviDeCroock)
  • Use in useSyncExternalStore (#3776, thanks @zalishchuk)


  • Consolidate benchmark workflow steps into a single reusable workflow (#3782, thanks @andrewiggins)
  • Upgrade bench dependencies (#3778, thanks @andrewiggins)
  • Upgrade workflow actions (#3777, thanks @andrewiggins)

Bug Fixes

  • Fix setState order (#3763, thanks @JoviDeCroock)
  • Fix duplicate ids with useId when Fragments are involved (#3758, thanks @marvinhagemeister)


  • Fix props not spreadable to <input> elements (#3764, thanks @mwszekely)

Bug Fixes

  • Fix webpack error when trying to import compat/package.json (#3755, thanks @akselander)
  • Fix nested fragments swapped incorrectly on conditional swap (#3738, thanks @JoviDeCroock)
  • Avoid synchronously adding setState callbacks (#3743, thanks @JoviDeCroock)
  • Fix signals not supported in HTML + SVG TypeScript definitions (#3747, thanks @marvinhagemeister)
  • Only remove nested DOM elements on unmount when necessary (#3741, thanks @developit)
  • Don't discard prop updates when nested state update is immediately cancelled (#3739, thanks @JoviDeCroock)
  • Align TypeScript definitions from react to refs and forward refs (#3713, thanks @PodaruDragos)
  • Add missing "types" field for preact/debug (#3732, thanks @marvinhagemeister)
  • Fix falsy data attributes not working (#3720, thanks @JoviDeCroock)
  • Ensure _mask property always has the same name in distributed version (#3721, thanks @JoviDeCroock)


New Hook: useId

Today we are announcing a new hook: useId. This hook creates stable unique identifiers that are consistent between server-side rendering (using preact-render-to-string) and client-side hydration. The useId() hook is primarily useful for generating identifiers for attributes like aria-labelledby and <label for="...">.

To enable useId() to generate consistent unique identifiers, please ensure you are using preact-render-to-string version 5.2.4 or newer for server-side rendering.

(#3583, thanks @JoviDeCroock)


  • Fix memory leak by cleaning up _parent, _dom and __hooks after unmount (#3709, thanks @JoviDeCroock)
  • Fix case where the ref property could be omitted from reused VNodes (#3696, thanks @JoviDeCroock)
  • Pass errorInfo to useErrorBoundary callback (#3689, thanks @marvinhagemeister)
  • Fix typescript definition for class | className (#3711, thanks @PodaruDragos)


  • Fix the mac arm build (#3697, thanks @gengjiawen)
  • Fix published JS formats after #3697 (#3702, thanks @rschristian)
  • Add todo benchmark and add a proxy package that uses preact/hooks (#3708, thanks @JoviDeCroock)
  • Add deprecation notice to render()'s replaceNode argument (#3700, thanks @rschristian)
  • Improve types for bare createElement() and h() calls (#3690, thanks @JoviDeCroock)
  • Add test for useId (#3716, thanks @JoviDeCroock)


  • allow for null return from fc (#3683, thanks @JoviDeCroock)


  • undo jsx-element removal (#3680, thanks @JoviDeCroock)


  • allow function component with children (#3676, thanks @JoviDeCroock)
  • ensure we iterate over all hooks (#3675, thanks @JoviDeCroock)


  • fix hooks calling shouldComponentUpdate without context (#3671, thanks @developit)
  • fix case where we set SCU multiple times (#3670, thanks @JoviDeCroock)
  • fix sync-external-store with zustand (#3663, thanks @JoviDeCroock)


  • fix useSyncExternalStore relying on changed render values (#3655, thanks @JoviDeCroock)
  • avoid crashing due to __hooks being null (#3651, thanks @JoviDeCroock)

Bug Fixes

  • Fix infinite loop in radix-ui which enqueues multiple state updates in the same tick (#3645, thanks @JoviDeCroock )
  • Fix effects run for suspended components in rare instances (#3643, thanks @JoviDeCroock )
  • Fix useSyncExternalStore not working with function values (#3633, thanks @marvinhagemeister )
  • Defer bailing out of updates to the render phase to align with React (#3621 + #3623, thanks @JoviDeCroock )
  • Fix some SVG attributes applied with wrong casing (#3615, thanks @iminside)


  • Update esbuild (#3630, thanks @marvinhagemeister )
  • Make demo compatible with node 16 and 18 (#3617, @gengjiawen )


We changed our debounce of our rendering to setTimeout!
Why? We've batched using microtasks for the past few major versions because it benchmarked well. This had a side-effect of flushing batched renders between event handlers, which can cause some strange behavior:


An additional benefit of this change is that code causing an infinite rendering loop will no longer result in an unresponsive browser tab. Rendering in a loop is now capped to the browser's maximum timer frequency (~250Hz), which makes it possible to pause and debug the code triggering an accidental loop.


We are adding support for the newly added React 18 hooks (apart from useId) (#3568, thanks @JoviDeCroock)


  • Adding types for 'part' attribute (#3595, thanks @rschristian)
  • prevent _suspended and _force from colliding (#3585, thanks @JoviDeCroock)


  • Add support for svg property shape-rendering (#3577, thanks @DannyvanderJagt)
  • Remove setState on unmounted component warning (#3576, thanks @ekwoka)


  • Fix allow return undefined in useMemo after skipped render (#3580, thanks @marvinhagemeister)
  • Fix incorrect useMemo return value after skipped render (#3579, thanks @marvinhagemeister)
  • Commit hooks in options.diffed (#3578, thanks @JoviDeCroock)
  • restrict "oninputCapture" conversion to just "oninput" vs "oninput*" (#3573, thanks @jramanat-oracle)


  • Improve unit tests to cover fix on #3573 (#3574, thanks @marconi1992)
  • Add _pendingValue to mangle.json (#3575, thanks @marvinhagemeister)
  • Clear pending state from repeated renders (#3567, thanks @JoviDeCroock)


  • Add export maps to the subpackages (#3565, thanks @JoviDeCroock)
  • Ensure both onchange and oninput callbacks are executes when typing (#3562, thanks @marconi1992)
  • Make createRoot / hydrateRoot compatible with React spec (#3560, thanks @3846masa)
  • Implement state settling in X (#3553, thanks @JoviDeCroock)


  • Fix size CI failing on node version missmatch (#3563, thanks @JoviDeCroock)


  • Add server.browser.js (#3544, thanks @JoviDeCroock)
  • Add textPath SVG type (#3546, thanks @backmeupplz)


  • improve compat types (#3534, thanks @JoviDeCroock)
  • support nodenext in TypeScript 4.7 (#3513, thanks @ilogico)
  • add missing containerInfo to portals (#3508, thanks @JoviDeCroock)


  • fix cleanup of debounceRendering hook after exceptions (#3530, thanks @robertknight)


  • fix Snyk sponsor link (#3533, thanks @developit)
  • add Snyk to sponsors (#3532, thanks @developit)
  • remove usages (#3528, thanks @mhmdanas)
  • fixes broken Slack shield in README (#3516, thanks @schalkventer)


  • Add new react-dom/client entry to compat (#3506, thanks @JoviDeCroock)


  • Simplify forwardRef and fix empty ref object (#3497, thanks @developit)


  • Add support for errorInfo (#3452, thanks @marvinhagemeister )
  • Allow for passing in multiple refs through forwardRef (#3494, thanks @JoviDeCroock)

Bug Fixes

  • Fix Incorrect translation of xlink:href attribute -> hhref (#3453, thanks @pguilbert)
  • Fix swapped jsx runtime __source and __self arguments (#3459, thanks @marvinhagemeister)
  • Ensure consistent format order for package entries (#3489, thanks @marvinhagemeister)
  • Reset useImperativeHandle ref to null when the component get unmounted (#3487, thanks @deadem)


  • Add missing defaultValue and defaultChecked typings (#3464, thanks @ilogico)


  • Fix test not cleaned up properly (#3457, thanks @marvinhagemeister
  • Fix fake timers not being reset on test failure (#3458, thanks @marvinhagemeister)
  • Remove unused devDependency (#3460, thanks @marvinhagemeister)
  • Update test dependencies (#3467, thanks @marvinhagemeister)
  • Improve karma test console logging (#3475, thanks @marvinhagemeister)
  • Fix karma error traces not being source mapped (#3476, thanks @marvinhagemeister)

As usual we recommend all users to upgrade.

Bug Fixes

  • Fix cursor reset in Safari in input field while typing by (#3448, #3450, thanks @marvinhagemeister)
  • Make sure compat is triggered in new jsx-runtime (#3445, thanks @Austaras)


  • fix effect ordering (#3416, thanks @JoviDeCroock)
  • Normalize CompositionEvent listeners in preact/compat (#3430, thanks @hpneo)


  • Change type of for better TypeScript compatibility with @emotion/react and @types/react. (#3431, thanks @rolftimmermans)


  • Use onInput instead of onChange in the README example (#3420, thanks @matthiask)
  • remove malfunctioning csb ci (#3417, thanks @JoviDeCroock)
  • Fix instructions for npm tag in CONTRIBUTING (#3380, thanks @andrewiggins)
  • Fix typo in release workflow (#3379, thanks @andrewiggins)
  • Automate building npm package for release (#3378, thanks @andrewiggins)

Due to a bug in the build of 10.6.3 we're republishing this was discovered in Astro


  • Fire useEffect in reverse component depth order (#3354, thanks @developit)
  • Map onFocus/onBlur to onfocusin/onfocusout (#3355, thanks @developit)


  • Add test for useEffect ordering with useMemo (#3360, thanks @andrewiggins)


  • Handle hooks that throw during cleanup (#3345, thanks @JoviDeCroock)
  • Include all package.json files in the export-maps (#3344, thanks @developit)


  • Fix switch check for excessDomChildren (fixes IE11) (#3342, thanks @JoviDeCroock)


  • Fix es5 warnings in local test runs (#3340, thanks @developit)


  • Adjust raf types (#3323, thanks @JoviDeCroock)
  • Suggest fix for useRef-types in hooks (#3222, thanks @JoviDeCroock)
  • Add component props to compat exports (#3321, thanks @JoviDeCroock)


  • Fix className leak (#3279, thanks @JoviDeCroock)
  • Support hydrating html comments (#3327, thanks @JoviDeCroock)


  • Fix tests in IE11 (#3264, thanks @developit)
  • Add jsx(-dev)-runtime to the export maps (#3320, thanks @JoviDeCroock)


  • Skip rendering contents on the client in compat (#3238, thanks @developit)
  • Nested Suspended trees may be missing _children (#3260, thanks @developit)
  • Manage camel-cased dominant-baseline attribute in preact/compat (#2859, thanks @nmondon)
  • Restrict camelCase prop renaming to non-custom elements (#3259, thanks @jramanat-oracle)
  • Fix bug in chrome where select values continuously rerender (#3226, thanks @JoviDeCroock)
  • Avoid leaking internal vnodes (#3106, thanks @developit)


  • Fix ref typing of forwardRef (#3214, thanks @itkrt2y)
  • Add focusin & focusout to type definitions (#3257, thanks @boarwell)
  • Add onBeforeInput attribute to type definitions (#3256, thanks @boarwell)
  • Add missed HTML attributes in the TS typings (#3246, thanks @rschristian)


  • Update babel.config.js (#3265, thanks @RRDAWLX)
  • Delete redundant previousComponent in hooks (#3271, thanks @RRDAWLX)
  • Update test dependencies (#3255, thanks @marvinhagemeister)


  • Compat: Add flushSync (#3094, thanks @zephraph)

Bug Fixes

  • Prevent eager child removal (#3210, thanks @JoviDeCroock)
  • Compat: Update Fake React Version (#3189, thanks @tim-on-github)
  • Fix react-spring error caused by augmented function contexts (#3165, thanks @developit)
  • Use for children arguments (#3143, thanks @fzzle)
  • Improve performance of vnodeId generation (#2978, thanks @developit)
  • Fix: should override children if null is provided as an argument (#3091, thanks @clyfish)


  • refactor(diff-index): reuse i to reduce size (-32b) (#3193, thanks @liuarui)
  • Simplify unmount logic (#3120, thanks @andrewiggins)


  • Fix type definitions (#3191, thanks @craftedsystems)
  • Fix undefined initializer case for useState type (#3185, thanks @rschristian)
  • Make typings deno compatible (#3079, thanks @lucacasonato)
  • Change typing of event.this to be never (#3147, thanks @JoviDeCroock)
  • Update signature of lazy to reflect behavior (#3139, thanks @JonasKruckenberg)
  • Improve typing of forwardRef (#3144, thanks @cmlenz)
  • Fix the useRef typing to include undefined when called without initial value (#3056, thanks @cmlenz)


  • Docs: Removing suggestion to install Preact CLI (#3204, thanks @rschristian)
  • Upgrade karma-esbuild to support M1 chips (#3153, thanks @marvinhagemeister)
  • Rely directly on (#3130, thanks @developit)
  • Add The Guardian as a Github backer (#3086, thanks @mchv)
  • Fix typo in issue template (#3067, thanks @rschristian)

Bug Fixes

  • Fix unable to reset tabIndex (#3062 + #3064, thanks @marvinhagemeister)
  • Add ESM entry for compat/server (#3059 + #3061, thanks @marvinhagemeister)
  • Fix unable to render bigint numbers (#3010, thanks @marvinhagemeister)
  • Fix reordering issue of memoized component when the component initially render null (#2988, thanks @tanhauhau)


  • Add decoding attribute (#3054, thanks @sumanthratna)
  • Add missing SVGFEFunc types (#3043, thanks @rschristian)


  • Update issue templates (#3058, thanks @marvinhagemeister)
  • Update esbuild to natively support Apple's M1 chip (#3028, thanks @marvinhagemeister)
  • Create separate trace log directories per benchmark (#3024, thanks @andrewiggins)
  • Reduce redundant preparation in bench scripts (#3013, thanks @andrewiggins)
  • Tests: Fix stale watch cache (#3012, thanks @marvinhagemeister)
  • Tests: Reduce CPU usage in watch mode (#3011, thanks @marvinhagemeister)
  • Tests: Fix Chrome 88 stack traces displayed wrong in terminal (#3008, thanks @marvinhagemeister)
  • Upgrade tachometer and add script to analyze browser trace logs (#3005, thanks @andrewiggins)
  • Use options.unmount instead of overriding component.componentWillUnmount (#2919, thanks @tanhauhau)
  • Update esbuild + karma-esbuild (#2991, thanks @marvinhagemeister)
  • Add a few minor tests (#2981, thanks @43081j)

This release includes an enhancement to our devtools integration. Via a babel plugin you can get more readable hook names to show up in devtools instead of dozens of useState hooks in devtools. Check out for more information.





Bug Fixes

  • Compat: Fix defaultValue not applied when value==null/undefined (#2957, thanks @marvinhagemeister)
  • Fix HTML comments breaking hydration (#2956, #2960 thanks @marvinhagemeister and @developit)


  • Tests: Improve console.logs (#2959, thanks @marvinhagemeister)
  • Remove redundant benchmark initialization (#2966, thanks @andrewiggins)
  • Fix pr-reporter condition (#2964, thanks @andrewiggins)
  • Report benchmarks on PRs from forks (#2961, thanks @andrewiggins)
  • Update size action to only run when src files change (#2962, thanks @andrewiggins)
  • Use artifact flow to report benchmarks results (#2953, thanks @andrewiggins)

:chart_with_upwards_trend: Bug Fixes

  • Fix unable to set contentEditable to false (#2938, #2939 thanks @marvinhagemeister + @developit)
  • Fix compat/jsx-dev-runtime missing in package (#2931, thanks @marvinhagemeister)

:golf: Code golfing

  • Golf element diffing [-17b] (#2942, thanks @developit)
  • Pass all props to createElement instead of just is [-5b] (#2943, thanks @developit)
  • Use try/catch for properties instead of an allow list, remove xlink: (#2939, thanks @developit)
  • Simplify diffChildren's handling of excessDomChildren and oldDom (#2941, thanks @andrewiggins)

:hammer_and_wrench: Maintenance

  • Tests: Alias react to preact/compat (#2946, thanks @marvinhagemeister)
  • Separate benchmarks into their own workflow (#2944, thanks @andrewiggins)
  • Simplify top-level render and remove dead code (#2940, thanks @andrewiggins)
  • Tests: Fix stack traces not sourcemapped (#2935, thanks @marvinhagemeister)
  • Fail build on missing compat entries in files entry (#2934, thanks @marvinhagemeister)
  • Add workflow_dispatch and restructure branch trigger (#2933, thanks @andrewiggins)
  • Tests: Fix vscode breakpoints not being hit (#2932, thanks @marvinhagemeister)
  • Fix incorrect sourcemap line mapping in tests (#2929, thanks @marvinhagemeister)

Bug Fixes

  • Fix contentEditable throwing when set to undefined/null (#2927, thanks @marvinhagemeister)
  • Compat: Add basic shims for some scheduler functions (#2912, thanks @marvinhagemeister)
  • Add jsx-dev-runtime package entry (#2920, thanks @sventschui)
  • Avoid overriding render method in Suspense (#2917, thanks @andrewiggins)
  • Fix updating suspended component (#2910, thanks @tanhauhau)


  • Fix Portal test not cleaning up container (#2925, thanks @marvinhagemeister)
  • Fix tests in IE11 (#2924, thanks @marvinhagemeister)
  • Fix karma IE11 target containing ES2015 syntax (#2923, thanks @marvinhagemeister)
  • Upgrade sinon dependencies to fix IE11 Promise error (#2922, thanks @marvinhagemeister)
  • Fix SauceLabs runner (#2918, thanks @andrewiggins)
  • Fix karma benchmarks not compiling (#2914, thanks @marvinhagemeister)
  • Remove babel-loader (#2911, thanks @andrewiggins)
  • Remove unused comment (#2909, thanks @marvinhagemeister)

Happy New Year to everyone 🎉 Let's kick of the year with a few welcome bug fixes regarding preact/compat 👍

Bug Fixes

  • Fix bug when re-rendering a suspended hydration node (#2903, thanks @andrewiggins)
  • Fix devtools error with portals (#2904, thanks @JoviDeCroock)
  • Fix child reordering with memo (#2896, thanks @andrewiggins)


  • Replace webpack with esbuild + babel in karma test runner(#2907, thanks @marvinhagemeister)
  • Rename "coverage" env to "COVERAGE" (#2906, thanks @marvinhagemeister)
  • Ensure expression is not marked for removal (#2905, thanks @marvinhagemeister)
  • Prepare test code to be run in ES2015+ environments (#2901, thanks @marvinhagemeister)
  • Fix invalid jsx comment (#2902, thanks @marvinhagemeister)
  • Fix console.log not showing up in browser (#2900, thanks @marvinhagemeister)
  • Improve hydration tests (#2899, thanks @andrewiggins)
  • Add support for pretty printing karma console logs (#2893, thanks @marvinhagemeister)

This is probably the last release for 2020. Thank you everyone for the amazing contributions over the year and we can't wait to see where Preact is going in 2021! Lot's of interesting ideas are being worked on 🎉

Bug Fixes

  • Correct _nextDom pointer if it is being unmounted (#2889, thanks @andrewiggins)
  • Updating /compat/server exports to work with import/export syntax and webpack 5 (#2873, thanks @SomethingSexy)
  • Remove arguments warning for useMemo/useCallback hooks (#2870, thanks @afzalsayed96)
  • Use strict equality checks when comparing VNode type (#2855, thanks @andrewiggins)
  • Fix ref not being removed from props with jsx-runtime (#2840, thanks @marvinhagemeister)
  • Compat: Don't convert onchange to oninput for input[type=range] in IE11 (#2817, thanks @gcraftyg)


  • Improve JSDoc comments (#2883, thanks @andrewiggins)
  • Use CSSStyleDeclaration for CSS property list (#2869, thanks @developit)
  • Add readonly attribute (#2868, thanks @rschristian)
  • Add defaultValue for select tag (#2848, thanks @Rafi993)
  • Update _original typings (#2830, thanks @marvinhagemeister)
  • Update csstype from version 2 to version 3 (#2829, thanks @bz2)


  • SimplifyPortal implementation (#2890, thanks @marvinhagemeister, @developit)
  • Simplify vnode re-use detection (-2 B) (#2863, thanks @marvinhagemeister)
  • Save 6 Bytes (#2844, thanks @marvinhagemeister)
  • Move child reodering to diffChildren (#2813, thanks @JoviDeCroock)


  • Add discussions and a csb template (#2875, thanks @JoviDeCroock)
  • In benches, abstract framework differences with createRoot API (#2866, thanks @andrewiggins)
  • Add filter benchmark (#2851, thanks @marvinhagemeister)
  • Update benchmarks (#2865, thanks @andrewiggins)
  • Add preactjs-gh-sponsor account to FUNDING.yml (#2861, thanks @JoviDeCroock)
  • Upgrade devDependencies (#2856, thanks @andrewiggins)
  • Add package tags (#2841, thanks @developit)
  • Trial codesandbox-ci (#2819, thanks @JoviDeCroock)
  • Fix compat/jsx-runtime missing in npm package (#2827, thanks @marvinhagemeister)

Bug Fixes

  • Throw when hook is invoked outside of render (#2816, thanks @marvinhagemeister)
  • Make jsx-runtime work when using an alias (#2805, thanks @JoviDeCroock)
  • Allow rendering from an effect (#2804, thanks @JoviDeCroock)


  • Add animateTransform tag type (#2822, thanks @HuHguZ)
  • Add displayName to context (#2820, thanks @max-voronov)
  • Improve style attribute types (#1797, thanks @mnkhouri)
  • General JSX types export for jsx-runtime, fixes TS4.1 compatibility (#2811, thanks @ddprrt)
  • Make ref types' current property non-optional (#2803, thanks @ivantm)


  • Remove circular vnode reference and golf implementation (#2517, thanks @JoviDeCroock)
  • Add hydration suspend tests (#2755, thanks @andrewiggins)
  • Fix prototype spies not being reset in tests (#2823, thanks @marvinhagemeister)

Bug Fixes

  • Reset hooks state when Suspense triggers (#2796, thanks @JoviDeCroock)
  • Run parent effects when child throws (#2794, thanks @sventschui)


  • Fix memo function types definition (#2793, thanks @dzhykaiev)

tl;dr: Bug-Fix only release that should get rid of the last className edge cases. We encourage everyone to upgrade.

Despite our effort to account for all edge cases regarding className handling in preact/compat, we got some reports of some missed ones. This release corrects those :tada:

This release contains a fix to increase compatibility with next.js that ensures that the error overlay will show up.

Bug Fixes

  • Emit error event for errors handled by an error boundary (#2784, thanks @sventschui)
  • Fix className descriptors on Element vnodes (#2786, thanks @developit)
  • Give precedence to className over class (#2782, thanks @JoviDeCroock)

This release fixes a regression in regards to class/className handling in preact/compat. We encourage everyone to upgrade.

Bug Fixes

  • Fix className normalization (#2774, thanks @JoviDeCroock)
  • Fix edge cases for thrown Promises in Suspense (#2776, thanks @kitten)


  • Replace custom script with check-export-map (#2777, thanks @marvinhagemeister)
  • Upgrade bench infra and add tachometer PR reporter (#2775, thanks @andrewiggins)
  • Optimizations for preact/jsx-runtime (#2771, thanks @developit)
  • Fix incorrect package export for jsx-runtime (#2769, thanks @marvinhagemeister)
  • Fix publishing error with jsx-runtime package (#2767, thanks @johakr)

New JSX-runtime functions

This has been a long time in the making for various virtual-dom based frameworks. Historically JSX was always transpiled to createElement function calls.

// input

// output, we need to move "foobar" to `props.children`
createElement("div, {}, "foobar");

While this has served us well and is very reliable, it has proven to be hard to optimize. Most of the things we do in our createElement function could by done by babel directly, thereby making it smaller and faster. This is very desirable for us as this function is called a lot in any application. It's part of the so-called hot-path.

And that's exactly what the new signature does. It removes the need for us to pull out key from props, add back children to props and just makes the implementation simpler. As a nice benefit users won't need to manually import h/createElement anymore :tada:

// input
<li key="foo">foobar</li>

// output
jsx("li", { children: "foobar" }, "foo");

Usage with babel:

// babel.config.js
module.exports = {
  plugins: [
    ["@babel/plugin-transform-react-jsx", {
      runtime: "automatic", // defaults to classic (classic == createElement calls)
      importSource: "preact", // NOT preact/jsx-runtime

Note that the JSX transformer in TypeScript is a work in progress and will likely be released as part of version 4.1. We're currently running into though, so the JSX typings are not found.


  • Add jsx-runtime support (#2764, thanks @JoviDeCroock, @marvinhagemeister)
  • Implement Suspend & Resume for both hydration and new tree construction (#2754, thanks @developit)

Bug Fixes

  • Fix unable to set progress value to 0 (#2757, thanks @marvinhagemeister)
  • Fix capturing and non-capturing listeners on the same element (#2740, thanks @devongovett)
  • Prevent cursor jumps inside contenteditable (#2701, thanks @sventschui)
  • Add length check for hooks dependency array (#2729, thanks @JoviDeCroock)
  • Fix rendering children as zero number (#2725, thanks @JiLiZART)
  • Avoid assigning to readonly style (#2723, thanks @JoviDeCroock)


  • Add mangle key for _suspended (#2765, thanks @marvinhagemeister)
  • Compat Optimizations (v11 backport) (#2752, thanks @developit)
  • Add version check to issue template (#2731, thanks @marvinhagemeister

tl;dr: A good handful of bug fixes make this release the ideal candidate to upgrade! Should be very safe to upgrade

Thanks to all the people who made this release possible! This is for everyone who took part in our discussions, helped report issues, did code contributions or just spread the word. Thank you all for another amazing release :raised_hands:


  • Remove all the bytes (#2665, thanks @developit)

Bug Fixes

  • Fix state turned readonly in update fn (#2717, thanks @marvinhagemeister)
  • Fix deprecation warnings flooding console with preact/debug (#2711, thanks @marvinhagemeister)
  • Initialize normalized props with undefined instead of null in preact/compat (#2695, thanks @aralroca)
  • Add React "secret or fired" shim for react-relay (#2692, thanks @marvinhagemeister)
  • Properly unset href on nullish value (#2693, thanks @marvinhagemeister)
  • Go back to undefined as default value for useRef (#2689, thanks @marvinhagemeister)
  • preact/debug: Add component stack to prop type validation error, do not pass ref to prop-types validation (fixes mui incompatbility) (#2685, thanks @sventschui)


  • Automatically add dom lib (#2713, thanks @Gerrit0)
  • Update useDebugValue typings to align with React (#2699, thanks @leader22)
  • Remove useErrorBoundary compat types (#2631, thanks @38elements)
  • Add support for IntrinsicElements in ComponentProps (#2680, thanks @remcohaszing)


  • Update slack link in (#2702, thanks @marvinhagemeister)
  • Fix invite link (#2697, thanks @JoviDeCroock)

tl;dr: This is a bug-fix only release and safe to upgrade :tada:

This release contains some amazing fixes by first time contributors! Thank you so much for everyone who filed issues or contributed PRs :heart:

Bug Fixes

  • Avoid touching DOM-attributes during hydration (#2679, thanks @JoviDeCroock)
  • Fix incorrect download attribute handling (#2674, thanks @marvinhagemeister)
  • Allow the same component to be suspended multiple times (#2661, thanks @tanhauhau)
  • Allow resolve promise after suspense unmounted (#2664, thanks @tanhauhau)
  • Throw when hook is used inside effect (#2672, thanks @marvinhagemeister)
  • Fix incorrect text node handling in diffElementNodes (#2658, thanks @perseveringman)
  • Default useRef to null (#2648, thanks @JoviDeCroock)
  • Fix calling setState in constructor (#2640, thanks @sventschui)


  • Change argument of useRef to optional (#2651, thanks @38elements)
  • Updated capture definition. (#2643, thanks @JonathanBristow)
  • Update preact/compat types (#2628, thanks @jeremy-coleman)


  • Run benches on linux VMs (#2595, thanks @andrewiggins)
  • Fix package.json "authors" field (#2635, thanks @developit)

tl;dr: This is a bug-fix only release and safe to upgrade :tada:

We've landed some very anticipated fixes and therefore thought to cut a new release not soon after :raised_hands:

Bug Fixes

  • Initialize children if they're null in suspense (#2570, thanks @sventschui)
  • Fix case where textarea doesn't reset state (#2615, thanks @JoviDeCroock)
  • Fix passing null to forwardRef (#2600, thanks @JoviDeCroock)


  • Make strokeMiterlimit accept a number as well (#2620, thanks @lfamorim)
  • Add feDropShadow definition (#2609, thanks @Somnid)


  • Add missing LICENSE files and fix submodule names (#2611, thanks @hbroer)
  • Fix typo in (#2603, thanks @futantan)
  • HTTPS fix for README image (#2602, thanks @developit)
  • Run same workflow on PR and master push (#2601, thanks @andrewiggins)

This is a bugfix-only release and updating is seamless. We encourage everyone to do so :+1:

Bug Fixes

  • Prevent Suspense from inadvertently modifying shared Component class (#2594, thanks @andrewiggins)
  • Fix Fragment edge case (#2551, thanks @JoviDeCroock)
  • Check for existence of requestAnimationFrame while cancelling effects it (#2573, thanks @Hydrophobefireman)
  • Handle setState in render (#2565, thanks @jamesb3ll)
  • Fix forwardRef passing object instead of null (#2567, thanks @marvinhagemeister)
  • Normalize value prop on textareas in compat (#2558, thanks @btk5h)
  • Prevent useReducer from mutating the previous returned result (#2550, thanks @JoviDeCroock)


  • Improve code coverage (#2596, thanks @andrewiggins)
  • Optimize unpkg entry: Commonjs plus globals default export (#2261, thanks @developit)
  • Share build output between action jobs (#2579, thanks @andrewiggins)
  • Add TypeScript for extending JSX types with custom elements (#2581, thanks @andrewiggins)
  • Update Node version in actions and format YAML files using prettier (#2577, thanks @andrewiggins)
  • Add GitHub action to run benches (#2560, thanks @andrewiggins)
  • Add many_updates benchmark (#2559, thanks @andrewiggins)
  • 🏌️‍♂️ rAF check (#2555, thanks @developit)
  • put rerenderCount on the Component prototype (#2552, thanks @JoviDeCroock)
  • Use "babel-plugin-transform-rename-properties" to consistently mangle properties (#2548, thanks @andrewiggins)

This is a hotfix for today's 10.4.2 release that:

  • addresses an issue with mobx-react (#2541, thanks @marvinhagemeister)
  • fixes a regression in useEffect cleanup callbacks (#2542, thanks @fuzetsu)

What a month we had! The weather is getting warmer and I think we can all enjoy a new refreshment in the form of a Preact release! The past weeks saw a good chunk of bug fixes and a bit of house keeping. Upgrades should be as straightforward as swapping out the version number in package.json and running npm install or yarn install once!

Introducing prefresh (experimental)

It was one of those miracle days where all the pieces fell into place just perfectly: @JoviDeCroock got a HMR (=hot module reloading) prototype up without any changes to Preact and running in a couple hours! With the biggset achievement being that it works amazingly well in keeping hooks state around.

Since then he was contacted by various maintainers of bundlers to collaborate on an ideal developer experience. Today, about a little more than a week later we have them ready to be tested. And we need your feedback to make it the best HMR experience we can! Please file any issue you come across!

Snowpack template

Oh and while we were at it @sventschui added a Preact template for snowpack! You can get it up and running via this line:

npx create-snowpack-app my-project --template @snowpack/app-template-preact


Preact sightings

Recently deno cut it's 1.0.0 release which is a huge achievement. It's a new spin on what node could look like if it would have started fresh in 2019 and we're excited where this experiment will lead to! Despite it being very early it made some waves in our community and we were filled with joy when we noticed that the website is built with our beloved framework!

Bug Fixes

  • Add noop React.StrictMode to compat (#2529, thanks @developit)
  • Use latest reducer function in useReducer (#2526, thanks @hadeeb)
  • Improve IS_NON_DIMENSIONAL for compatibility with animation-iteration-count (#2523, thanks @viko16)
  • Polyfill prototype setter in debug (#2514, thanks @JoviDeCroock)
  • Fix hydrate export in compat (#2511, thanks @hadeeb)
  • Fix creating multiple roots from useEffect (#2493, thanks @JoviDeCroock)


  • Add StrictMode to compat/src/index.d.ts (#2530, thanks @38elements)
  • Add loading attribute to HTMLAttributes TypeScript interface (#2521, thanks @gerardo-rodriguez)


  • Fix indentation (#2528, thanks @Vincent-Carrier)
  • Fix test on IE11 by wrapping the spy helper (#2524, thanks @JoviDeCroock)
  • Remove unnecessary cloning of props (#2516, thanks @hadeeb)
  • Iteratively diff children and convert array children to Fragments (#2507, thanks @andrewiggins)
  • Update focus tests to better match user behavior (#2506, thanks @andrewiggins)
  • IE11+ -> IE11 (#2499, thanks @38elements)
  • Reorganize render test file (#2487, thanks @andrewiggins)
  • golf effect cleanup (#2494, thanks @JoviDeCroock)
  • Remove processingException check (#2483, thanks @JoviDeCroock)
  • Reduce unnecessary DOM attribute reads (#2486, thanks @andrewiggins)
  • Remove unnecessary excessDomChildren creation (#2491, thanks @andrewiggins)
  • Add update benchmark from js-framework-benchmark (#2489, thanks @andrewiggins)

tl;dr: This release allows our devtools extension to inspect hooks. Apart from that it includes the usual round of bug fixes.

We have a nice little present for you and that is hooks are now fully supported in Preact Devtools 0.5.0 :tada: The extension is currently awaiting approval in browsers stores and your browser will automatically update to it in the following days.

Screenshot from 2020-04-19 21-10-06

Both @andrewiggins and @JoviDeCroock went full on bug hunting mode and got some neat fixes in! We also saw an awesome contribution from @davidje13 who found an error in our types for memo :+1:

But the true star from the show is without a doubt that we finally have updated our typings to bring back the marquee element. @developit himself took the honors and made sure that developers can continue to use this element in their demo applications.

Bug Fixes

  • Add support for hooks inspection via devtools (#2480, thanks @marvinhagemeister)
  • Make warn effectively warn instead of throwing (#2477, thanks @JoviDeCroock)
  • Support node13 (#2451, thanks @JoviDeCroock)
  • Use setProperty to set "value" and "checked" properties (#2472, thanks @andrewiggins)
  • Normalize props on cloneElement (#2469, thanks @JoviDeCroock)
  • Set value/checked on custom-elements (#2465, thanks @JoviDeCroock)
  • Add support for context displayName (#2454, thanks @marvinhagemeister)


  • Add <marquee> typings (#2466, thanks @developit)
  • Account for defaultProps when wrapping components with memo (#2461, thanks @davidje13)


  • Run benchmarks with v8, master, and local builds (#2475, thanks @andrewiggins)
  • Reduce number of builds in actions (#2476, thanks @andrewiggins)
  • Add npm prepare script (#2473, thanks @andrewiggins)
  • Upgrade devtools adapter (#2471, thanks @marvinhagemeister)
  • Tachometer benchmarks (#2462, thanks @andrewiggins)

tl;dr: This release contains some very amazing improvements to hydration and to performance when memoized vnodes are used. We recommend everyone to upgrade :tada:

We understand that the past weeks have been very strange for everybody across the world. We've spent that last weeks mainly focusing on making sure our families and loved ones are safe and taken care of. Whether you're using Preact at work or in a sideproject we hope that this release brings you a little bit of joy and makes your day a little bit brighter :stars:

Strictly equal vnodes bail out of render

When an vnode is equal to the one from the last render we will successfully bail out of rendering. This is a performance optimization many state libraries frequently make use of. The most well known of those is probably react-redux. We've wanted to add this for the initial Preact X release but had to postpone due to not having found the proper solution back then. In the following months we've passed around various ideas on how to best solve this and it wasn't until last month when it finally clicked and the pieces fell together. @JoviDeCroock had a prototype up running in a few days and has spent a lot of time into making sure that this performance optimization works in all scenarios. We can't stress enough how much of an accomplishment this is. This is really amazing work by @JoviDeCroock and we're over the moon that it has finally landed in Preact :tada:

hydrate falls back to render for new subtrees

When doing SSR there are cases where the DOM tree and the vnodes don't match. This can lead to a lot of problems, but for now we handle situations a bit more gracefully when there is no existing DOM node present. If we encounter that, we just opt out of hydration for that tree and revert back to doing a full diff. In the future we plan to add more warnings to preact/debug for that.


  • Implement strict-equality for vnodes (#2386, thanks @JoviDeCroock)
  • Fallback to render when subtrees are inserted on hydration (#2438, thanks @JoviDeCroock)
  • Add owner stack for invalid child warning (#2416, thanks @marvinhagemeister)

Bug Fixes

  • Fix error messages logged by failed prop type checks (#2434, thanks @robertknight)
  • Skip setProperty for known bypass cases (key, children) (#2213, thanks @developit)
  • Improve handling of exceptions thrown during act callback (#2433, thanks @robertknight)
  • Ensure ref is mutable even if a DOM node is inserted into it (#2422, thanks @JoviDeCroock)
  • Fix Context not re-rendering when reset to defaultValue (#2420, thanks @JoviDeCroock)
  • Disable normalization of string vnodes (#2410, thanks @JoviDeCroock)


  • Update act type signature (#2444, thanks @ddayguerrero)
  • Add _patchedLifecycles to compat/src/internal.d.ts (#2408, thanks @38elements)


  • Docs: Fix simple typo, stucture -> structure (#2440, thanks @timgates42)
  • Fix CONTRIBUTING typo (#2417, thanks @futantan)
  • Use double equal with typeof (#2409, thanks @polemius)
  • Enable saucelabs-connect (#2411, thanks @developit)
  • Move from Travis to Github Actions (#2401, thanks @JoviDeCroock)

This is a maintenance release, upgrading should be free, please do report it in case you encounter any issues.

render-queue sorting

Preact batches all rendering work and executes from the top of the Virtual DOM tree to the bottom. However, if new rendering tasks were added during an existing render, they were processed without regard for their depth in the tree.

Thanks to a clever fix from @jviide, Preact's render queue is now immutable. Any new tasks added during rendering are placed into a second batch.

material-ui integration

A peculiar issue users were seeing with material-ui related to a ref never getting populated, we went very deep into the codebase and found out that our forwardRef was a bit too eager, at creation it would already start forwarding. We moved this to a later point, now just before the vnode will get diffed the ref will be forwarded.


  • Fix mui Popover integration (#2403, thanks @JoviDeCroock)
  • Fix defaultValue with re-render (#2392, thanks @aralroca)
  • Sort new renderqueue items (#2396, thanks @jviide)


  • Fix stopPropagation override for IE11 (#2390, thanks @JoviDeCroock)
  • Use createEvent since InputEvent and new Event won't work in IE11 (#2400, thanks @JoviDeCroock)
  • Fix useErrorBoundary hook callback type (#2397, thanks @Sasha-Sorokin)
  • Update cloneElement typings (#2388, thanks @ddayguerrero)

tl;dr: Some minor changes which make this release safe to upgrade for everyone!

Another week, another Preact release! It seems like the previous one wasn't too long ago, but there are already so many cool changes in master that we're eager to bundle them in a neat release!

Much improved conditional rendering

One insanely cool and very important change was done by @andrewiggins, who woke up one day and found a very elegant solution to handling conditionally rendered elements. Most virtual-dom-based frameworks mark a falsy result with some sort placeholder (sometimes referred to as "holes"), so that the diffing algorithm can ensure that elements are not moved around needlessly.

It's not just for performance though as they are some real world consequences to moving nodes around. The most common annoyance is <input>-elements losing focus whenever a parent is moved. With this change we are pretty confident that we squashed all known issues on that front :+1:

Improved SVG attribute casing

SVG also received a big change by @steveharrison . It's his first contribution Preact and he already knocked it out of the park with an excellent PR. HE went through the whole SVG spec and noticed that we didn't match some of the weird casings of SVG-Attributes properly and his PR remedies that beautifully! :100:

Preact sightings

@pksjce finished her YouTube series where she reads through a portion of the Preact source code. With that she helped us tremendously in spotting areas in code which lacked comments and finally pushed us to create a proper "Contributing" guide. If you are considering contributing to Preact, this short document is well worth a read as it contains an overview of the repo's structure and answers for the most common questions regarding our code. That said if you feel like something is missing or you do have troubles understanding some sections of the source, please reach out to us! We're here to help and feedback about friction points is crucial to making Preact better for everyone :+1:

Checking our official website you may have noticed some slight changes here and there. They're mostly to simplify navigation or to give our docs a more fitting structure. The long term plan is to integrate our learnings about the most common support questions we get and fill in those spots. @NJalal7 spotted a few of those areas and even found a bug in Preact in the process that we we're promptly able to fix :raised_hands:

Thank you so much to everyone who contributed code, helped us in narrowing down issues or participated in making Preact even better. Preact wouldn't be were it is now without you all :heart:


  • Compat: Add isPropagationStopped fn to event (#2378, thanks @reznord)
  • Compat: Add isDefaultPrevented fn to event (#2377, thanks @teodragovic)
  • Large performance boost in preact/debug (#2362, thanks @developit)

Bug Fixes

  • Fix event.isPropagationStopped() (#2380, thanks @38elements)
  • Fixed SVG attribute names not being converted to the correct attribute names in the DOM. (#2366, thanks @steveharrison)
  • Fix incorrect warning on setState inside componentWillMount (#2367, thanks @marvinhagemeister)
  • Fix static hydration (#2365, thanks @JoviDeCroock)
  • Fix hook outside of component test (#2359, thanks @JoviDeCroock)
  • Remove warning for useEffect/useLayoutEffect (#2358, thanks @JoviDeCroock)
  • Improve null placeholder DOM placement (#2355, thanks @andrewiggins)


  • Fix options.event type definition (#2381, thanks @38elements)


  • Add comment to clarify seemingly redundant string concatenation (#2369, thanks @mhmdanas)
  • Rename some variables to increase legibility (#2361, thanks @andrewiggins)
  • Combine searches in excessDomChildren into the same code block (#2356, thanks @andrewiggins)
  • Fix failing test by defaulting to empty array (#2353, thanks @JoviDeCroock)
  • Add new test file for null placeholders (#2352, thanks @andrewiggins)

tl;dr: Another bug-fix only release. It's safe to upgrade and we encourage everybody to do so :+1:

It's sunny today and I haven't been outside yet, so I'll make it quick: Those pesky ref TypeScript errors when used with a CSS-in-JS library should be no more! So if you're using styled-components, emotion, goober or any other CSS-in-JS library, this update is for you! :100:

@robertknight found that false values where not special cased for aria-* attributes as they have a different way of treating boolean values compared to the DOM. Many boolean-like attributes like aria-checked have three states:

  • true element is checked
  • false element is unchecked, but it's possible to check it
  • undefined (default) element can't be checked

As usual thank you so much for everyone who helped make Preact better by contributing code or reporting issues! You all rock :+1:

Bug Fixes

  • Add support for false value in aria-attributes (#2347, thanks @marvinhagemeister)
  • Remove array provided to callback in and .forEach (#2326, thanks @mhmdanas)
  • Fix missing index (#2322, thanks @JoviDeCroock)


  • Match useErrorBoundary type with componentDidCatch (#2332, thanks @intrnl)
  • Fix incompatible ref typing with ReactElement (& popular react libraries) (#2099, thanks @xiel)
  • Make useErrorBoundary's callback param optional (#2320, thanks @intrnl)


  • Fix failing useImperativeHandle tests (#2346, thanks @marvinhagemeister)
  • Create (#2342, thanks @JoviDeCroock)
  • Node "exports" adjustments (#2327, thanks @guybedford)
  • Add package.json to package.exports (#2319, thanks @MylesBorins)

tl;dr: Just a minor bug-fix-only release. Safe to upgrade for everyone.

We've been notified of an issue with the way we used the new exports feature that was introduced with Node 13, so we wanted to get out patch release as quickly as possible. Despite that we managed to include several other fixes in such a short timeframe that are worthy to mention.

Run tests against the minfied production artifact

This is big for us. @andrewiggins did an amazing PR which modifies our testing infrastructure to execute the tests against the minfied production bundles that are published to npm. This greatly reduces any chances of us not catching bugs that may exist in transpilers or the custom minify config we're using. And Andre promptly found a few misconfigurations already. Most of you propably didn't run into these issues as they are somewhat in the edge case area, but it's amazing to have a tool to automatically check our code for an mishaps :100:

A new size bot

In the early days of the Preact X rewrite we made a promise to ourselves in that we would check the effects on size for each PR. We started by printing out all the sizes of our exports via microbundle, but we did still have to compare those manually against what's in master. Both @kristoferbaxter and @developit have been joining forces and created a bot which does that automatically. As soon as the pipeline on a PR succeeds it will add a comment listing all the size differences :+1:


Bug Fixes

  • Fix className not being applied when set to an empty string with preact/compat (#2309, thanks @JoviDeCroock)
  • Run karma tests against build output (#2300, thanks @andrewiggins) :heart:
  • Fix: Resolves Node submodule subpath error (#2304, thanks @4cm4k1)


  • Add to umd and make browser a modular export for future bundlers (#2311, thanks @JoviDeCroock)
  • Add root exports (#2310, thanks @JoviDeCroock)
  • Removes warning from tests by removing console.log in render.test.js (#2305, thanks @theZieger)

tl;dr: This release contains a good number of bug fixes and we encourage all users to upgrade.

A little bit of time has passed since our last release and we're excited to ship another one, making Preact even more robust! The fixes nearly touch all packages and further improves compatibility with third-party libraries :tada:

If you glance at the contributor names, you'll notice a few new ones there. It's safe to say that we were amazed and super ecstatic by the amount of new first time contributors to Preact! :raised_hands:


  • Include support for customised built-in elements (#2266, thanks @defx)
  • Upgrade devtools adapter to support Profiler and bring back preact/devtools import (#2246, thanks @marvinhagemeister)

Bug Fixes

  • Suspended components should rerender through shouldComponentUpdate (#2125, thanks @andrewiggins)
  • Reduce reads of dom.nextSibling (#2294, thanks @andrewiggins)
  • Preserve state when using placeholders (#2295, thanks @andrewiggins)
  • Fix not flattening result (#2287, thanks @marvinhagemeister)
  • Fix error when setting size to an invalid value (#2285, thanks @marvinhagemeister)
  • Fix wrong SVG attribute for clipPathUnits (#2251, thanks @friebe)
  • Fix both class and className being enumerable (#2280, thanks @marvinhagemeister)
  • Fix className patch not applied to props (#2279, thanks @marvinhagemeister)
  • Bailout when hook throws an error (#2193, thanks @JoviDeCroock)
  • Avoid removing existing dom nodes on subsequent replaceNode calls (#2274, thanks @JoviDeCroock)
  • Fix shouldComponentUpdate getting called on setState after forceUpdate (#2258, thanks @laino)
  • Remove process.env.NODE_ENV check from preact/debug which broke browsers (#2257, thanks @marvinhagemeister)


  • Allow null as an initial value for useRef (#2281, thanks @armujahid)


  • Rename _lastDomChildSibling to _nextDom (#2297, thanks @andrewiggins)
  • Improve code coverage (#2299, thanks @andrewiggins)
  • Update mangle.json with Suspense prop rename (#2298, thanks @andrewiggins)
  • Fix SVG polygon test failing on IE 11 (#2288, thanks @marvinhagemeister)
  • Try out new node submodule exports (#2283, thanks @JoviDeCroock)
  • Add section about reporting bugs (#2278, thanks @marvinhagemeister)
  • Improve CONTRIBUTINIG + comments (#2277, thanks @marvinhagemeister)
  • Add size action (#2270, thanks @developit)
  • Prevent postinstall from running on installation (#2271, thanks @JoviDeCroock)
  • Add test coverage for createElement (#2273, thanks @zubhav)
  • Fix custom element tests failing in IE (#2272, thanks @marvinhagemeister)
  • Fix failing IE test (#2267, thanks @marvinhagemeister)
  • Add info for first time contributors (#2265, thanks @marvinhagemeister)
  • Add unit tests to check proper component unmounting (#2195, thanks @timon-witt)
  • Add npm ci to speed up travis (#2255, thanks @JoviDeCroock)
  • Add package-lock.json (#2254, thanks @JoviDeCroock)

This release corrects an issue regarding hydration that was found in yesterdays 10.2.0 release :tada:

Bug Fixes

  • Fix duplicate text node with hydrate() (#2238, thanks @JoviDeCroock)

Happy belated New Years to everybody :tada: We hope you enjoyed the holidays and had some time off to recharge :+1: Our very first release in 2020 brings two new features and the usual round of bug fixes :100:

New useErrorBoundary hook

There is a new hook called useErrorBoundary which allows you to catch errors that are thrown by any child components. It's essentially the hook version of componentDidCatch.

// 1. parameter is null or the error that was caught
// 2. paremeter can be called to reset the state
const [err, reset] = useErrorBoundary();

// Optional: You can pass a callback function that will
//  be executed when an error occurs:
const [err] = useErrorBoundary(() => callMeMaybe());

Usage example:

// Example component that will throw an error on render
const SomeComponent = () => {
	throw new Error("fail");

const App = props => {
	const [err] = useErrorBoundary();

	if (err) {
		return <p>Something went wrong...</p>;
	} else {
		return <SomeComponent />;

Lazy works with non-default export

This PR was one of the smallest ones, but something that makes working with different kind of lazy loaded modules a lot easier. Previously lazy would always use the default export of the imported module. With this change it's now possible to use it with any export.

// Look ma, no default export
const LazyFoo = lazy(() => import("./Foo").then(m => m.MyComponent));

On top of that we have the usual round of bug fixes. We'd like to thank everyone who reported them and helped us make Preact even better. Thank you so much!! :+1:


  • Add useErrorBoundary hook (#2205, thanks @JoviDeCroock)
  • Allow lazy() usage with non-default imports (#2212, thanks @developit)

Bug Fixes

  • Fix incorrect ref value on sibling vnodes (#2217, thanks @JoviDeCroock)
  • Fix stale closure in error boundary (#2225, thanks @JoviDeCroock)
  • Fix Text nodes being re-rendered unnecessarily (#2215, thanks @developit)
  • Shorten and correct renderToString dependency error (#2207, thanks @developit)
  • Support combination of getDerivedStateFromError and componentDidCatch (#2200, thanks @JoviDeCroock)
  • Fix compat hydration (#2206, thanks @JoviDeCroock)


  • Add onReset/onFormData to Form Event types (#2209, thanks @thesmartwon)


  • More README updates (#2235, thanks @developit)
  • Modernize our README (#2232, thanks @JoviDeCroock)
  • Update package metadata (#2230, thanks @developit)
  • Add more test cases for Suspense (#2229, thanks @sventschui)
  • Fix renderer tests by using sinon global (#2220, thanks @JoviDeCroock)
  • Update JSDoc comments (#2187, thanks @soulhat)

tl;dr: A tiny maintenance release, which helps with debugging Preact apps.

This release is a lot smaller compared to our usual ones, but we deemed one feature important enough to have in users hands that we made this release. And that's component stacks which we hope will reduce the issue count in our tracker slightly :tada:

On top of that we want to congratulate @jamesb3ll for his first-time contribution to Preact :1st_place_medal: He found an issue and filled it with every detail one can imagine (codesandbox is awesome!). But instead of stopping there, he tinkered a bit and found a genius fix for it! Thank you for your PR :+1: :four_leaf_clover:

Component Stacks

Whenever you include preact/debug you get a lot of hints and warnings about how you can make your application better. But sometimes it was hard to tell where the error originated from. To resolve that we automatically append a component stack trace telling you directly which component threw the error.

class Foo extends Component {
  constructor(props) {

    // Doesn't do anything, `this.state = { foo: true }`
    // should be used instead.
    this.setState({ foo: true });

  render() {
    return <div>foo</div>;

function Bar() {
  return <Foo />;

function Baz() {
  return <Bar />;

The above code will print the following warning to the browser's console:

Screenshot from 2019-12-16 20-55-21

With the stack appended at the bottom it's much easier to track down the source :100: To get those beautiful file and line mappings, make sure that you have @babel/plugin-transform-react-jsx-source enabled in your babel config :+1:


  • Add component stack in debug warnings (#2179, thanks @marvinhagemeister)

Bug Fixes

  • Fix componentWillReceiveProps not called on child component when parent is queued in the same commit (#2186, thanks @jamesb3ll)


  • Workaround for sinon esm bundle (#2188, thanks @marvinhagemeister)

tl;dr: This release adds support for the highly anticipated preact-devtools extension. It's in an early preview state, but it has proven to be very useful already for inspecting a component tree in our internal testing. Apart from that there is a new SuspenseList component to control loading in lists and the usual round of bug fixes.

Christmas comes early in the form of another feature packed Preact release :tada: We're particular proud of this one as it represents the results of a lot of work behind the scenes. Especially when it comes to the devtools.

Developers, Developers, Developers! :wrench:

For the longest time we've been able to reuse the react devtools extension that was (as the name implies) written specifically for React. We did this by hooking ourselves into the init procedure and shimming in a conversion layer that translated our inner workings to something React would use under the hood. Over the past year we've kept up with all the internal changes of React's private structures, but it took us more and more time to make sure that the integration wasn't breaking or running into weird edge cases.

Faced with a choice we decided to pursue the development of our own extension specifically written for Preact. This way we are not affected by any breaking changes on React's side and have the possibility to extend the devtools with custom UI, like for the Composition-API PR #1923 .

That said the extension is not what we would call final yet. It's more of an early preview, akin to an alpha release. Despite bugs you may encounter, we found it useful enough in our testing that we didn't want to hold back any longer.

Download it here:


SuspenseList :1234:

SuspenseList is a new component that can control the order in which any child suspensions are revealed. Take a list of images for example. Due to the browser firing the requests to download them in parallel, the images may appear in any order. This can be a bit jarring, when some sort of appear animation is involved. With SuspenseList we can force all images to appear at the same time, inorder or in reverse.

In the following example A will appear first, followed by B even if C was loaded before B. And finally C will appear.

// `revealOrder` can be one of 'forwards', 'backwards' or 'together'
<SuspenseList revealOrder="forwards">
  <Suspense fallback={<span>Loading...</span>}>
    <A />
  <Suspense fallback={<span>Loading...</span>}>
    <B />
  <Suspense fallback={<span>Loading...</span>}>
    <C />


  • Add support for preact-devtools (#2148, thanks @marvinhagemeister)
  • SuspenseList optimisations (#2121, thanks @jviide)
  • Add SuspenseList component (#2063, thanks @prateekbh)

Bug Fixes

  • Suspense should support unmounting suspender (#2134, thanks @sventschui)
  • Add correct this type for event handlers (#2166, thanks @marvinhagemeister)
  • Prevent crash in IE when setting type attribute (#2147, thanks @Rafi993)
  • Always use lower cased touch events in compat (#2120, thanks @sventschui)
  • Fix wrong DOM order on suspend inside Fragment (#2107, thanks @jviide)


  • Add onToggle event to TypeScript defs. (#2151, thanks @xorgy)
  • Re-export FunctionComponent from preact/compat (#2087, thanks @jokester)
  • Fix internal Suspense-related typings (#2117, thanks @jviide)
  • Specify valid dir property values (#2108, thanks @antonk52)

Golf :golf: :golfing_woman:

  • Optimize createElement (#2135, thanks @developit)
  • Rename useMemo _callback to _factory (+0 B) (#2131, thanks @andrewiggins)
  • Remove redundant if clause in suspense _catchError (#2119, thanks @sventschui)
  • Consolidate VNode compat options (-62 B) (#2116, thanks @andrewiggins)


  • Disable benchmarks on CI (#2167, thanks @marvinhagemeister)
  • Fix minor spelling and grammar issue (#2165, thanks @ivanjonas)
  • Update perf tests for Preact X and enable on master (#2158, thanks @andrewiggins)
  • Rewrite touch event tests to not use internals (#2157, thanks @andrewiggins)
  • Improve test DOM helpers (#2152, thanks @andrewiggins)
  • Rewrite some tests to no longer rely on internals (#2132, thanks @andrewiggins)
  • Fix cross browser tests assertions (#2127, thanks @andrewiggins)
  • Modularize compat src and tests (#2124, thanks @andrewiggins)
  • Add test to cover hooks debug helper (#2115, thanks @andrewiggins)
  • Add test for lifecycles and state of a delayed suspending compo… (#2114, thanks @andrewiggins)

tl;dr: This release is a bug fix only release and all users are encouraged to update.

This week saw many cool improvements surrounding our TypeScript definitions. Thanks to an amazing contribution from @lukeshiru the event target is now correctly inferred for all native elements. This alone should remove many manually casted event arguments in your code :tada:

Together @JoviDeCroock and @cristianbote set their minds on fixing a few newly reported issues surrounding refs and the like. Personally, I'm pretty impressed how quickly they could identify and resolve the issues. Much respect to you two :+1:

As the year is coming to an end @andrewiggins did some house-cleaning and found various places where we could save even more bytes! I don't know how he does it and it's just amazing to witness so much pure talent!

Beside that, the changes mainly revolve around maintenance tasks. We've switched to prettier for automatic code formatting, lowering the barrier for new contributors even more. The formatting is automatically applied on each commit via a git-hook, and everything will be taken care of for you :100:

We also saw two exciting contributions from Googlers: @jridgewell found a very hard to spot unnecessary case in a regex we use to append px to certain CSS values and @jakearchibald found an html attribute we missed in our typings :tada:

Like in our past release we'd like to take a moment to thank everybody who contributed, not just code but also made the time to write bug reports. Thank you so much :+1:

Bug Fixes

  • Cleanup changing refs correctly (#2055, thanks @JoviDeCroock)
  • Ensure renderCallbacks are called when sCU bails out (#2081, thanks @JoviDeCroock)
  • Handle the stale ref for forwardRef (#2075) (#2076, thanks @cristianbote)

Golf :golfing_woman:

  • Simplify hook scheduling logic (-17 B) (#2085, thanks @andrewiggins)
  • Improve tree-shakeability (-13 B) (#2079, thanks @andrewiggins)
  • Simplify ternary expressions (-7 B) (#2049, thanks @andrewiggins)
  • Remove CSS custom property check from IS_NON_DIMENSIONAL (#2046, thanks @jridgewell)


  • Add types for currentTarget on event handlers for IntrinsicElements (#2084, thanks @lukeshiru)
  • Improve ref typings for IntrinsicElements (#2070, thanks @lukeshiru)
  • Add as html attribute to TypeScript defs (#2068, thanks @jakearchibald)


  • Add funding field to package.json (#2096, thanks @developit)
  • Upgrade tests to use Babel 7 (#2094, thanks @andrewiggins)
  • Rewrite createContext tests to no longer import internal data (#2090, thanks @andrewiggins)
  • Remove preact-charts from README (#2092, thanks @pmkroeker)
  • Update README section about preact/devtools (#2091, thanks @peterswallow)
  • In tests, import code under test by name instead of relative path (#2086, thanks @andrewiggins)
  • Replace __p to __ in mangle.json (#2044, thanks @38elements)
  • Make all .json files use 2-space (#2078, thanks @developit)
  • Adding Intergram to the demos list (#2064, thanks @idoco)
  • Improve formatting (#2071, thanks @andrewiggins)
  • Improve formatting (#2066, thanks @andrewiggins)
  • Add automatic formatting via prettier (#2065, thanks @marvinhagemeister)
  • Change Preact v8 "browser" field to "umd:main" (#1963, thanks @andrewiggins)

This release fixes a build issue that caused errors when using effect hooks.

  • Add missing _renderCallbacks mangle configuration (#2060, thanks @robertknight)

This release corrects an issue where a debug warning was printed incorrectly to the console, that (rightfully) confused users. So we wanted to fix that as quick as possible :+1:

Bug Fixes

  • Fix setState warning always being printed (#2057, thanks @marvinhagemeister)


  • Queue layoutEffects in component render callbacks array (+0 B) (#2050, thanks @andrewiggins)
  • Separate debug tests into multiple files and fix some bugs in debug (#2047, thanks @andrewiggins)

tl;dr: This is release contains mostly bug fixes and some size reductions. We encourage everyone to upgrade.

Just a week has passed since the last release and there are already an exciting number of new commits in master. Hackoktoberfest has had really positive effects on us and we're excited to see some new contributors in this release :100:

As you can see from the changelog: @andrewiggins is currently on a byte removing spree, so I thought it'd be appropriate to list them in their own category :tada: A few others joined him and marie kondo'ed everything that didn't spark joy in us!

Besides some great savings, there are new debug warnings for components and fixes for our Suspense implementation :tada:


  • Add debug warnings when calling setState or forceUpdate on an unmounted component (#2037, thanks @andrewiggins)

Bug Fixes

  • Support re-suspending with <Suspense> (#2025, thanks @andrewiggins)
  • Add unpkg aliases (#2032, thanks @developit)
  • Fix ref not always called in useImperativeHandle (#2021, thanks @JoviDeCroock)

Golf (size reductions)

  • Inline coerceToVNode inside of toChildArray (-21 B) (#2040, thanks @andrewiggins)
  • Remove unused mount check in context Provider (-6 B) (#2039, thanks @andrewiggins)
  • Golfed render (#2045, thanks @MohammedSheikhIbrahim)
  • Remove useless return from eventProxy (#2026, thanks @jridgewell)
  • Rewrite useImperativeHandle to use useLayoutEffect (-35 B) (#2003, thanks @andrewiggins)
  • Re-purpose renderCallbacks as a general per-component commit queue (#2011, thanks @andrewiggins)


  • Add nonce to JSX HTMLAttributes types for better Content Security Policy support. (#2035, thanks @calvinf)
  • Remove internal import from compat types (#2018, thanks @andrewiggins)
  • Fix internal vnode typings (#2015, thanks @pmkroeker)


  • Remove end of line in compat/mangle.json (#2053, thanks @38elements)
  • Add _afterPaintQueued and _fallback to mangle.json (#2043, thanks @38elements)
  • Remove OpenCollective postinstall Banner (#2033, thanks @developit)
  • Update preact/compat in readme (#2029, thanks @developit)
  • Fixed some typos and grammatical mistakes. (#2028, thanks @MohammedSheikhIbrahim)
  • Add _force and _lastDomChild to mangle.json (#2023, thanks @developit)
  • Add _suspensions to mangle (#2019, thanks @JoviDeCroock)
  • Add npm script to run compat TS tests (#2017, thanks @andrewiggins)

tl;dr: This is a standard bug-fix release with no new features. We encourage everyone to upgrade

Wow, we've been overwhelmed with the reactions to our final Preact X release! We saw a huge uptick in npm downloads to 200.000 per week :tada: Another exciting announcement is that Google AMP is officially using Preact under the hood. We've receivied many more thank you notes (and even stroopwafels!) from companies using Preact. Those range from small companies to big enterprise ones, where Preact is used in a wide span of different environments.

We preactively allocated the weeks after the big launch for a period of bug-fixes only in case something slipped through. It was admittedly a more conservative decision after our long alpha and beta period, but we wanted to make sure that you all would have a butter smooth experience no matter what :stars: It's safe to say that it went really well and we've only received a couple bug reports so far :tada:

In the short amount of time that has passed since the release, we managed to squash a good portion of those! Thank you so much to everyone for reporting bugs and helping us track them down! You rock :+1: :100:

Bug Fixes

  • Resolve attributes of reused nodes that weren't present in virtual-dom (#1987, thanks @JoviDeCroock)
  • Fix stale context values (for createContext-API) (#2005, thanks @JoviDeCroock)
  • Properly flush nested setState callbacks (-6 B) (#2010, thanks @andrewiggins)
  • Import and re-export hooks explicitly to allow for webpack tree shaking (#2006, thanks @davidbailey00)
  • Removing reference to preact-context library (#2001, thanks @jackbravo)
  • Fix forceUpdate enqueued child update being skipped (#1988, thanks @marvinhagemeister)
  • Append Portal node to container instead of prepend (#1971, thanks @toraora)
  • Always pull _force flag from component (#1984, thanks @marvinhagemeister)
  • Fix typos in JSDoc (#1973, thanks @polemius)
  • Fix replaceNode not always taking effect (#1970, thanks @JoviDeCroock)


  • Remove null from VNode.type TS definition and add some TS tests (#1994, thanks @andrewiggins)
  • Add _force to internal.d.ts (#1990, thanks @38elements)
  • Improve VNode typings (#1979, thanks @andrewiggins)


  • Golf shouldComponentUpdate (#1980, thanks @JoviDeCroock)
  • Add Songsterr to Real-World Apps section (#1972, thanks @followdarko)


tl;dr: Preact X is the next major version of Preact fully packed with features like Fragments, Hooks, componentDidCatch, Test-Utils, Debug-Warnings, many compatibility fixes and so much more :tada:

It's finally happening! After months of hard work we've crossed the finish line and are over the moon with excitement to finally mark Preact X as stable. We'd like to thank everybody who tested it and submitted bug reports.

We originally planned to release a sort-of migration release as version 9 with just the breaking changes from X, but that got canned because many users reported that the upgrade process was easy enough and didn't warrant a long migration period in-between. In fact we got many reports that the upgrade could be done in under an hour, despite some of the breaking changes in X, making the need for a migration release even less desirable.

What's new?

Preact X ships with several major features and we combined them all in a single document on our site. If you're upgrading an existing Preact 8.x project, we got you covered with a detailed upgrade guide.

To give a quick summary of the new features:

  • Fragments
  • componentDidCatch
  • preact/hooks addon
  • preact/test-utils addon
  • createContext API
  • compat moved to core
  • Plethora of compatibility fixes
  • Many new warnings in preact/debug
  • Same 3 kB size as Preact 8

Again, we highly recommend checking out our new site and specifically the what's new section.

Changes since RC 4

Bug Fixes

  • Rewrite shouldComponentUpdate handling to take more edge cases into account (#1931, thanks @JoviDeCroock)
  • Fix UNSAFE_* lifecycles being overwritten in compat (#1946, thanks @marvinhagemeister)
  • Fix PureComponent rerendering when __source changes (#1950, thanks @JoviDeCroock)
  • Fix default argument in useState not applied in rare cases (#1948, thanks @JoviDeCroock)
  • Change .forceUpdate() to participate in the update queue (#1939, thanks @developit)
  • Fix vnode._children should keep their type as array when diffing (#1924, thanks @cristianbote)
  • Allow numeric CSS values to be 0 (e.g. opacity) (#1927, thanks @JoviDeCroock)
  • Fix unnecessary rerender on equal contexts (#1925, thanks @JoviDeCroock)


  • Add disableRemotePlayback to HTML Attributes (#1955, thanks @JoviDeCroock)
  • Add volume to HTML Attributes (#1938, thanks @jessicabyrne)


  • Prevent mangling of __source and __self (#1958, thanks @JoviDeCroock)
  • Add documentation on how to do releases (#1928, thanks @marvinhagemeister)

So uhm... just yesterday we've published RC2 and we've mentioned that it would be likely the last RC before going final. Turns out that fate had other plans. One seemingly minor change to our jsx constructor function lead to pretty weird and nasty bug depending on whether the code was run in use strict mode or not. @jviide wrote up a great summary on how this issue came to be.

Bug Fixes

  • Avoid creating circular children refs in createElement (#1917, thanks @JoviDeCroock)


  • Fix PureComponent not passing generic types along (#1920, thanks @amelekhin)

tl;dr: This release contains a lot of bug fixes in many areas and we encourage everyone to upgrade. We're confident that this is the last rc release before marking X as stable.

It's time for another Preact release :tada: We've spent the past weeks on make
Preact as robust as we can. Most fixes are ones you all submitted to our
tracker. This is super awesome and we wouldn't be where we are without all your

On top of countless fixes, a few minor features found their way into the
package like isValidElement that can be used to check if something is valid to
render, meaning it's a valid child that was created by h/createElement.

The test utils also received much love and we're very impressed with how quickly
@robertknight was able to land support for async callbacks and nested calls
to act :100: This is useful in cases where triggering an effect or state change
involves async steps, such as waiting for a fetch call to resolve.

Preact Devtools are coming

We think it'd be good to give a setSate of the union here about where we are
with the devtools. As many of you are aware we've always depended on the
react-devtools extension for a long time now. We were very excited to
integrate with version 4, not just because of the new featureset, but also
because the adapter and protocol is so much better than before.

We got very far, but despite of all our efforts we ran into blocker issues with
the expected order of events that need to be sent to the extension. Our
internals differ quite a bit and after trying for weeks to get it right we
ultimately went back to the drawing board.

It became clear that just writing our own extension would be less resource
intensive and would make it easier for us to maintain. It's pre-alpha right now,
but we expect to mature in the coming weeks/month. Here is a screenshot as a
little sneak peek:


Very early pre-alpha preview of preact-devtools

We'll keep you posted! Here is the full list of changes in this release:


  • Add isValidElement to core (#1861, thanks @marvinhagemeister)
  • Throw error when passing plain objects as children (#1858, thanks @marvinhagemeister)
  • Add support for form attribute on buttons and inputs (#1863, thanks @sventschui)
  • Warn when calling setState in a constructor (#1857, thanks @marvinhagemeister)
  • Implement support for async act callbacks and nested calls to act (#1854, thanks @robertknight)

Bug Fixes

  • Fix nested setState calls with accurate this.state (#1748, thanks @JoviDeCroock)
  • Fix useImperativeHandle handles after rendering (#1909, thanks @JoviDeCroock)
  • Fix shouldComponentUpdate leading to invalid DOM without children (#1888, thanks @JoviDeCroock)
  • Add shouldComponentUpdate check for context.Consumer (#1901, thanks @cristianbote)
  • Fix replaceNode argument not always replacing node (#1900, thanks @JoviDeCroock)
  • Fix incorrect dom pointer with shouldComponentUpdate (#1871, thanks @marvinhagemeister)
  • Fix IE11 regressions (#1856, thanks @marvinhagemeister)
  • Fix undefined styles not being cleared (#1853, thanks @marvinhagemeister)
  • Fix act not flushing effects/updates if global effect/update queues are non-empty before act call (#1851, thanks @robertknight)
  • Support adding refs to memo'ed components (#1860, thanks @sventschui)
  • Tag forwardRef & memo proxy components as React components (#1844, thanks @developit)
  • Fix IE11 not setting initial select value (#1838, thanks @marvinhagemeister)
  • Avoid accessing fn.prototype where possible (#1835, thanks @developit)
  • Only destroy DOM on first render (#1832, thanks @marvinhagemeister)
  • Flatten children array as it is diffed (#1716, thanks @andrewiggins)
  • Optimize creating array of childrens (#1743, thanks @Connormiha)


  • Fix compat types (#1752, thanks @marvinhagemeister)
  • Add key to all jsx elements (#1887, thanks @marvinhagemeister)
  • Fix type definitions for getDerivedStateFromProps and getDerivedStateFromError (#1874, thanks @38elements)
  • Add VNode.constructor to internal type definitions (#1810, thanks @38elements)


  • Add info message about react-devtools v4 (#1908, thanks @marvinhagemeister)
  • Add back Code of Conduct from Preact 8 branch (#1897, thanks @marvinhagemeister)
  • Make source files non-executable (#1894, thanks @jridgewell)
  • Skip form attribute test on IE11 (#1868, thanks @marvinhagemeister)
  • Re-enable coveralls (#1867, thanks @marvinhagemeister)
  • Disable coveralls until their outage is resolved (#1866, thanks @marvinhagemeister)
  • Delete .flowconfig (#1855, thanks @38elements)
  • Remove Flow type definition (#1846, thanks @38elements)
  • Remove a duplicate test in render tests (and add additional child node checks) (#1847, thanks @OrKoN)
  • Exclude Edge from running devtool tests (#1839, thanks @marvinhagemeister)
  • Remove double build for TravisCI (#1837, thanks @cristianbote)
  • Exclude devtools tests from coverage (#1808, thanks @marvinhagemeister)
  • Fix test in IE by sorting attributes. (#1836, thanks @marvinhagemeister)

This release is a maintenance release and all users of the 8.x release line are encouraged to upgrade to it.

  • Fix devtools bridge not working with react devtools v4 (#1876)

This is a maintenance release and fixes a minor issue with the packaging of the devtools import. All users on the 8.x release line are encouraged to upgrade.

tl;dr: This release contains many little fixes and we encourage all X users to upgrade.

As we're nearing closer to the actual release we're hoping to sweeten the wait with another rc-release :tada: While the docs are coming along nicely we have a preview of our upcoming migration guide to Preact X from 8.x. We have a little polish left to do, but apart from that the new docs are basically ready :fingers_crossed:

But back to the actual release! This time the fixes touch a broad area in Preact. There are a few for Portals, some for onTransition* or onAnimation* events and the usual round of browser or typing PRs.

It's arguably less feature packed than previous releases, but that's a really good sign for the release candidate phase. It means that X is mature and is in great shape for going gold :+1: :100:


  • Diff props when replacing a node and don't diff when hydrating (#1786, thanks @JoviDeCroock)

Bug Fixes

  • Fix lazy not forwarding refs (#1826, thanks @JoviDeCroock)
  • Fix Chrome Headless running on WSL (#1696, thanks @developit)
  • Use internal reference for hydration flag (#1802, thanks @developit)
  • Fix animation and transition events handlers not being recognized (#1804, thanks @JoviDeCroock)
  • Fix IE11 incompatability with input type="range" (#1823, thanks @JoviDeCroock)
  • Add additional test for createPortal -> normal vnode (#1805, thanks @JoviDeCroock)
  • Fix Portal children always being mounted (#1781, thanks @marvinhagemeister)
  • Fix debug crash with hooks import (#1773, thanks @JoviDeCroock)


  • Add Partial to setState (#1779, thanks @pmkroeker)


  • Fix typos across preact repository (#1796, thanks @kittenking)
  • Fix typo (#1784, thanks @38elements)
  • Upgrade xvfb config for Travis CI (#1822, thanks @prateekbh)
  • Add Web Maker to real world app list (#1762, thanks @chinchang)

This is a maintenance release for Preact's 8.x versions. We'd like folks to try out Preact X, but if you're still using 8 we have you covered.

This release includes support for createRef(), and updated TypeScript definitions.

tl;dr: This is mostly a bugfix only release, with one notable exception. Due to popular demand we reversed our decision to remove support for string styles and brought them back :four_leaf_clover: All users on the next tag are encouraged to upgrade :+1:

You may have already noticed the rc suffix in the release number and that is because we're finally out of beta :+1: rc stands for roughly complete... uh... release candidate and this means that a final Preact X release is really close :checkered_flag: We do wanted to give it another phase of testing before going final though and it gives us a bit time to get our docs in shape.

8.x will be maintained further :wrench:

Don't worry if there is something you would have loved to see in X, but that didn't make the cut. The final X release is more of a sign that we think it's stable and maybe even more so than 8.x ever was :tada: This also means that we can focus more on adding new features and reduce our current maintenance overhead of working on two release lines simultaneously. The upgrade should be pretty seamless for everyone and we'll publish a complete migration guide along with the final X release. If you for some reason can't update to X don't worry. We'll keep maintaining the 8.x release line for a good while.

Now You’re Thinking With Portals

This release contains some noteworthy fixes to our Portal-Component. But not just that, we also added back support for string styles due to popular demand. Originally we removed them to save bytes, but it turns out that this feature is way to useful not to have. Additionally it aligns better with out philosophy with being "closest to the DOM". Thank you'all for everyone who participated in that journey and helped us make the right decision moving forward :+1: :100:

SSR Boost :speedboat:

This change has been cooking for a while and plays well along with the research @developit and @housseindjirdeh have been doing about hydration. When you look at the way SSR works, you'll notice that pretty much the complete diff phase is redundant. The HTML that is sent to the client matches the vnode tree completely, so there isn't much point in comparing changes. The thing is that we can't remove it completely though, because we still need to attach event listeners. For that case we introduced a faster code path which bypasses most of the diffing. After the initial render is done, Preact will continue with the usual diff mode.

Note: This may be a breaking change if you are sending an incorrect DOM structure to the client and relied on hydrate to correct that for you. To fix this make sure to sent HTML that matches the initial vnode tree on the client.

Rock solid ecosystem

At this point we'd like to give a shoutout to @robertknight who continues to quietly maintain enzyme-adapter-preact-pure. It's rock solid already and it's only getting better. Be sure to check it out :nerd_face:

Without further ado: Here is the full changelog of our first (p)release candidate :1st_place_medal:


  • Add back support for string styles (#1744, thanks @marvinhagemeister)

Bug Fixes

  • Add requestAnimationFrame fallback when tab is not focused (#1763, thanks @calebeby)
  • Move Code of Conduct into .github dir (#1765, thanks @developit)
  • Move eslintignore into package.json (#1764, thanks @developit)
  • Fix various scenarios with Portals (#1749, thanks @JoviDeCroock)
  • Minor debug enhancements (#1755, thanks @marvinhagemeister)
  • Bypass props during hydration (#1697, thanks @developit)
  • Fix uncontrolled inputs not changing value (#1760, thanks @JoviDeCroock)
  • Replace catchRender with catchError (#1742, thanks @andrewiggins)
  • Warn on invalid table DOM structure (#1745, thanks @JoviDeCroock)
  • Fix replaceNode not unmounting when diffing twice with replaceNodea (#1723, thanks @JoviDeCroock)
  • Fix up compat types and tests (#1740, thanks @andrewiggins)
  • Golf sibling DOM handling (#1737, thanks @andrewiggins)
  • Add return type to _childDidSuspend (#1735, thanks @pmkroeker)
  • Fix compat render not destroying existing DOM (#1729, thanks @marvinhagemeister)

tl;dr This is a bug-fix-only release and all users are encouraged to update. A final release is in sight :tada:

It's the summer and while hopefully most of you will be able to enjoy the time
outside we couldn't pass the opportunity to let our latest beta release free
into the world! This might be the last beta we'll publish before going gold,
so stay tuned :wink: For this reason we focused purely on shaking all bugs out
and make this the most stable preact release we can :+1: :100:

Most notably this includes some rethinking of how we deal with Fragments
internally. Over the past weeks we received bug reports which all seemed to be
related and it turns out they were! They all shared the problem that the sibling
order was different after a component update. We all got our heads together
and found a better internal implementation for Fragments that's a lot more
sound theoretically. It should fix all ordering issues for good :+1: :checkered_flag:

Although this release is quite and we've set our sights on a final release we're
already working on getting the Preact debug adapter in shape for the upcoming
react-devtools v4 :tada: It's not just more performant, but also adds the
hooks panel right in the devtools. More on that soon :wink:

Again, you are awesome

As always Preact wouldn't be what it is today without you all. Whether you've
been helping us squash bugs, joined feature discussions or just spread the word,
we're really thankful to be part of such an amazing community. We even got to
meet some of you at this years JSConfEU!

With all said: We can't wait to unleash the final release soon! If you're new
to the beta releases, don't worry. The final release will be accompanied with
a migration guide :+1:


Because of the internal restructuring preact-render-to-string needs to be updated to at least version 5.0.4.

Bug Fixes

  • Restore debounceRendering after act (#1683, thanks @JoviDeCroock)
  • Fix cross browser assertions (#1708, thanks @marvinhagemeister)
  • Bubble up Component dom changes up the virtual tree (+51 B) (#1700, thanks @andrewiggins)
  • Begin rendering with diff instead of diffChildren and other golf ⛳ (#1715, thanks @andrewiggins)
  • Implement useRef with useState (#1679, thanks @JoviDeCroock)
  • Fix falsy event values beeing added (#1712, thanks @cristianbote)
  • Minify names of externally exposed private functions (#1711, thanks @andrewiggins)
  • Ensure correct unmount (#1687, thanks @JoviDeCroock)
  • Correct Portal unmounting and props diffing (#1691, thanks @JoviDeCroock)
  • RFC: Privatize some options (-7 B) (#1692, thanks @andrewiggins)
  • Begin diff with next DOM sibling in forceUpdate (#1689, thanks @andrewiggins)
  • Replace ancestorComponent with vnode parent pointer (+5 B) (#1688, thanks @andrewiggins)
  • Delete React debugging props __self and __source (#1690, thanks @mxstbr)
  • Consistently use _children & combine Fragment and Component diffing (-73 B) (#1658, thanks @andrewiggins)
  • Don't use typeof check for h (#1676, thanks @JoviDeCroock)


  • Update compat typings (#1703, thanks @pmkroeker)
  • Retype style to error on strings (#1675, thanks @pmkroeker)


  • Update suspense so tests only rely on public API (#1724, thanks @andrewiggins)
  • Disable Safari in Saucelabs tests (#1706, thanks @marvinhagemeister)
  • Add redux to demo app (#1705, thanks @marvinhagemeister)
  • Clean up scratch DOM after tests (#1701, thanks @andrewiggins)
  • Separate lifecycle tests into separate files (#1702, thanks @andrewiggins)
  • Add toEqualNode chai assertion (#1680, thanks @andrewiggins)
  • Run ESLint on all source and test files (#1686, thanks @andrewiggins)
  • Add preact-charts to Component Libraries (#1667, thanks @pmkroeker)

tl;dr: We're excited to be one step closer to a final Preact X release! It's packed full with the addition of Suspense, lazy, performance improvements and the usual round of bug fixes :tada:

Internally we've been referring to this one as the "Hitchcock"-Release. @jviide came up again with the very fitting release title :+1: We're proud to welcome @sventschui as the newest addition to our team! And oh boy did he join us with a bang! :tada:

The Suspense Is Real

@sventschui went ahead and added basic support for both the Suspense component and lazy() to preact/compat. With these in place it is now a lot easier to do proper code-splitting. Just have a look at this example on how they can be used together:

import { Suspense, lazy } from "preact/compat";

const Other = lazy(() => import('./OtherComponent'));

function Foo() {
  return <Suspense fallback={<div>Loading...</div>}>
    <Other />

In the snippet above the Other component will only be displayed once it's loaded. Until then the Suspense component allows the user to display any fallback content making it ideal for any sort of spinners for example :+1: :1st_place_medal:

This was one of the remaining road blocks in getting Next.js to work with Preact X :tada: Note that our implementation is still considered an experimental preview :clock1030:

The golfing continues :golf: :golfing_man:

Last cycle we had a lot of fun finding ways to make Preact even smaller! In fact, we had so much fun that we continued a bit to do so leading up to this release :100: These size optimizations are really important, because they allow us to offset the byte cost for new features while staying within our self imposed byte size limit :whale:

Faster hydration :zap: :checkered_flag:

Following @developit and @housseindjirdeh's talk on Progressive Hydration at Google I/O'19, we've landed the first changes to support a more ideal way of handling hydration. Note that this is formally a breaking change, but it won't likely cause you any trouble. What's different is that existing server-rendered DOM element attributes will no longer be removed during hydration. This translates to a huge performance benefit for boot-up time, which means your page gets interactive and ready-to-go noticeably sooner if you are doing Server Side Rendering or prerendering :rocket:

Removed string styles

We removed support for string styles in favor of setting style properties only with objects. This aligns our behavior with various other virtual-dom based libraries out there :heavy_check_mark: Note that this is a breaking change from 8.x and you may need to update your code:

// before
<div style="color: LightGoldenrodYellow;" />

// after
<div style={{ color: "LightGoldenrodYellow" }} />

This one was long on our list of possible ways to cut down on size. Nonetheless we are aware that this might be a controversial change. If you have a lot of string styles or want to continue using them, you can use preact-string-styles to patch this behavior back into Preact X. If you don't agree this change, please let us know!

Preact Sightings :atom_symbol:

Sometimes we need a bit inspiration on how to build complete Applications with Preact. We were super stoked to see that one of the demos at Google I/O uses our library and can be inspected here on GitHub. The demo is a minesweeper-like game called Proxx that makes clever use of some advanced web features like Web Workers and WASM. Be sure to check it out!

If any of you wonderful people happen to be at JSConfEU in Berlin this weekend, let's meet in person! Both @cristianbote and I (@marvinhagemeister) will be attending, and we have plenty of stickers with us :wink:

In closing we've been super thankful for every PR or bug report we received in the past cycle. They are crucial to make Preact rock solid and help us find edge cases we may not have thought of. Thank you all!



  • Introduce Suspense and lazy (#1593, #1638 thanks @sventschui)
  • Don't read attributes during hydration (#1596, thanks @developit)
  • Update README with the proxx demo (#1654, thanks @talentedandrew)
  • Make consistent use of key check logic (-12 B) (#1651, thanks @andrewiggins)
  • Update links for the new preactjs org (#1649, thanks @JoviDeCroock)
  • Support JSX-sourcemaps (#1628, thanks @JoviDeCroock)
  • Simplify key matching technique (#1637, thanks @developit)
  • Remove the unused bundlesize dependency (#1641, thanks @JoviDeCroock)
  • Add travis-size-report to the CI (#1633, thanks @wardpeet)
  • Revert the lookup on documentView since this introduced a regression (#1631, thanks @cristianbote)
  • Show useEffect warning instead of throwing error (#1623, thanks @yuqianma)
  • breaking: Remove support for style as string and other golfing (-32B) (#1606, thanks @cristianbote)
  • Golf Hooks (-11B) and compat (-18B) (#1602, thanks @JoviDeCroock)
  • Code golf preact.js.gz size down by 53 B ⛳️ (#1599, thanks @jviide)
  • Store text node's text content as VNode.props instead of VNode.text (#1600, thanks @jviide)

Bug fixes

  • Update Fragment DOM log with null placeholder behavior (#1661, thanks @andrewiggins)
  • Prevent crash with nullish ref (#1657, thanks @JoviDeCroock)
  • Remove props.key even when key === 0 or key === "" (#1607, thanks @jviide)
  • Fix unmount behavior when using replaceNode (#1647, thanks @JoviDeCroock)
  • Fix react-hot-loader compatibility by not checking on vnode ref (#1644, thanks @JoviDeCroock)
  • Fix this reference in componentWillUnmount under context Consumer (#1627, thanks @sventschui)
  • Ignore dangerouslySetInnerHTML during hydration (#1595, thanks @developit)
  • Don't compare vnodes when oldVNode has no dom reference (#1617, thanks @JoviDeCroock)
  • self is not available in non-browser environments (#1618, thanks @cristianbote)
  • .some should not be used for effect invoke/cleanup (#1613, thanks @JoviDeCroock)
  • Only warn once about argumentless effects (#1625, thanks @JoviDeCroock)
  • Warn about missing preact-render-to-string dependency (#1603, thanks @JoviDeCroock)
  • Insert portal children instead of overwriting the container (#1629, thanks @JoviDeCroock)


  • Add types to compat (#1609, thanks @pmkroeker)
  • Add types for Suspense/lazy (#1619, thanks @pmkroeker)

tl;dr: This release contains important bug fixes to our reconciler and a security fix.
We highly recommend to upgrade to this version if you are running a past alpha
or beta release of Preact X.

Code-Golf to the max :golf: :golfing_woman:

As mentioned in our past release notes we spent more time on making preact even
smaller. It didn't take long until @andrewiggins found ways to cut down close
to 40 bytes in just a few hours. We don't know how he does it, but the bytes
are surely afraid of him by now! Amazed by that headstart @jviide soon followed
with a PR of his own which removed another 30+ bytes. He's been helping us
with loads of performance improvements in the past weeks and you may already
know him from his outstanding contributions to htm,
but this is his very first PR to Preact. Be sure to give him a high-five when
you see him somewhere :tada:

Lazor sharp focus :telescope:

The temptation was real and @JoviDeCroock tackled one of the bigger fish that
was back on our minds for a while: Our focus workaround. Due to past bugs in
our reconciler during the alpha phase we had to add a workaround so that a
focused input wouldn't lose focus when sibling elements were moved or removed
completely. The workaround took some toll on the final build size and jovi
managed to finally crack the nut and made it possible to remove that workaround.

After just a few days we're happy to report that close to 100 bytes had to pack
up their things and leave the repo :point_right: We're super happy with the result and have
surpassed our initial approximations on possible savings :checkered_flag:

VNode hardening :muscle:

One thing that's very important for us is making sure that we make it easy to
do the right thing by default regarding security. For that all modern frameworks
prevent the most common Cross-Site-Scripting Attacks (short: XSS). Frameworks
that are based on the virtual-dom are unique in that regard as most exploits
rely on some way to inject a malicious string through innerHTML.

Preact 8.x included a protection for the following scenario:

// Malicious JSON received from server or created
// from user input via JSON.parse() in app code
const evil = {
  type: "div",
  props: {
    dangerouslySetInnerHTML: "<script>alert('xss')</script>"

function App() {
  // Inject our evil vnode
  return <div>My name is {evil}</div>;

render(<App />, document.body);

The exploit basically comes down to a possibility of a user being able
to inject any js object as a virtual-dom node (= vnode) and in effect
being able to call dom.innerHTML = evilString. Note that this
requires either a compromised or insecure server or an input field which
is parsed via JSON.parse() and put back into JSX unmodified to pull of
the exploit successfully. This is why we think it's a low priority security

We take any security issue seriously and have added a similar protection
mechanism to Preact X :+1: Thanks goes to @JoviDeCroock and @wardpeet who did
the inital prototype.

Say hello to useDebugValue and useImperativeHandle :wave:

These two hooks are lesser known than useState and the like, but are sometimes
used in third-party libraries. useDebugValue is especially important to
remain compatible with the upcoming mobx-react which relies a lot on hooks
internally. With these 2 hooks added we are now 100% compatible with the react
ecosystem on that front :tada:

Easier hydration :heavy_check_mark:

As we all know server-side-rendering (short: ssr) is a neat way to improve
the time to first paint. This is especially important if you're working for
a newspaper or magazine where the bottom line is very dependent on performance.
First-Time contributor @LukasBombach championed an improved way to directly
replace a DOM node with a render() call. This is very useful on a site where
sections are rendered independently from each other.

It works by being able to pass a third replaceNode parameter to render.
We were not only impressed by the attention to detail in his PR, but also by
the incredible description and info-graphics around the changes. This was
beyond stunningly awesome :+1: Check out the description in his PR for more information.

Loads of little fixes :wrench:

As usual this release is packed with a bunch of fixes and minor performance
improvements. Most notably are correctness fixes and improvements to animation
event handling. On top of that we added an example page with styled-components
to test with. We knew some users had issues with it and Preact 8.x in the past
so we wanted to make sure that it will work right out of the box with Preact X.
And the good news is that we haven't found any issues so far :tada:

In general we fell like we're reaching a stage with Preact X where it is pretty
stable and mature at this point. A final release is likely not too far off in
the future :100: :wink:

But enough talk, here is the full list of changes:

  • Reduce size by golfing down some pieces 🏌️‍♂️ (-39 B) (#1578, thanks @andrewiggins)
  • Remove focusElement (#1548, thanks @JoviDeCroock)
  • Code golf diffChildren size down by 33 B ⛳️ (#1580, thanks @jviide)
  • Prevent json injection (#1528, thanks @JoviDeCroock)
  • Add replaceNode parameter to render() (#1557, thanks @LukasBombach)
  • Add support for global event handlers like animation and transition (#1590, thanks @cristianbote)
  • Add styled-components example (#1574, thanks @marvinhagemeister)
  • Add useImperativeHandle (#1556, thanks @JoviDeCroock)
  • Add useDebugValue hook (#1554, thanks @marvinhagemeister)
  • Warn about hooks outside render and/or components (#1509, thanks @JoviDeCroock)
  • Improve nested effect rerenders in act (-49 B) (#1546, thanks @andrewiggins)
  • Fix _lastDomChild disregarding placeholders (#1587, thanks @marvinhagemeister)
  • Fix useState can potentially add to the state queue and make the _dirty call neglect this (#1584, thanks @JoviDeCroock)
  • Fix infinite loop because of props mutation (#1577, thanks @marvinhagemeister)
  • Fix Error boundary not applying in array cases (#1572, thanks @JoviDeCroock)
  • Fix prevent crash when there is no last DOM child node (#1568, thanks @JoviDeCroock)
  • Fix input value not in specified range (#1435, thanks @marvinhagemeister)
  • Fix hoisting of components without DOM (#1559, thanks @marvinhagemeister)
  • Fix wrong state references (#1465, thanks @mochiya98)
  • Disable travis' email notifications (#1560, thanks @marvinhagemeister)
  • Slight improvements to code coverage (#1558, thanks @marvinhagemeister)
  • Run tests on MacOS 10.13 + Safari 11 (#1555, thanks @developit)


  • Update type definition (#1581, thanks @38elements)
  • Ts fixes (#1565, thanks @ForsakenHarmony)
  • feat: adds microdata attrs types (#1585, thanks @Dangoo)

tl;dr: This release contains several important improvements to our reconciler (the part that is responsible for moving the DOM nodes around). Because of that we highly recommended everyone who is on one of the previous alpha releases to upgrade.

Easter is coming up, and we have enough changes in master to warrant a release :tada: During the past weeks we managed to resolve lots of bugs. Not just your standard bugs, but loads of the trickier ones :+1: For the first time in a long while we are below the 100 issue mark :tada: With release we feel confident that it can be used in a wider target audience. Our featureset is complete, and we even added a lot more than was initially planned for Preact X. If you're missing something where you feel like that it must absolutely be added in the initial release and can't wait for the next minor one, please voice your opinion in our issue tracker.

Fragments considered stable

The most notable change is a very welcomed refactoring of our reconciler to fix known issues we had with Fragments. @andrewiggins spent a lot of time the last weeks on getting this one right. What's most impressive about this is that he didn't just fix one or two of the issues surrounding Fragments, and instead blew us all away by squashing all of them in one go.

In classic Andre fashion the PR is very thorough with detailed annotations about the changes in each commit. He just has that incredible talent for stepping back and assessing the situation with fresh eyes.

Demo inspired by

Next-level conditional rendering

One cool optimization that our new code base allowed us to do is introducing the concept of placeholders (often referred to as "holes") in our renderer. These placeholders allow us to skip a bit of work when updating conditionally rendered elements like in the following example:

  {condition && <Foo />}
  {!condition && <Bar />}
  <p>vroooooom 🚀</p>

Seeing that this is quite a common pattern in Preact-based apps, we are very excited about the performance improvements of that technique. Another positive side effect is that it opened up the chance to land further enhancements to keyed and unkeyed children!


Depth-based component updates

Once thing that was bugging us, is that even with version X, Preact would do more work than necessary when nested updates are involved. This happened when a child component enqueued an update via setState and later one of the parent components does the same thing, we'd render the child component twice (Child -> Parent -> Child). This happened because we would process the queue in the order the updates where added. We can effectively remove a whole render by making our processing depth-aware. Our new code detects that we can optimize the ordering by rendering the parent first which will automatically update the child component.

This work was initially started by @JoviDeCroock and later joined by the whole team. We're quite happy with the result and noticed the enhanced rendering speed in our own apps :100:

Official adapter for enzyme

For a while now @robertknight has devoted his time to greatly enhance our testing story. He wrote an adapter for the popular enzyme testing library from Airbnb. It even works with both Preact 8.x and Preact X. We've been using it quite a bit in our own projects and wanted to mark it as an official package.

At some point in the future we're planning to move all the other libs over to the organization, too. But there is no concrete timeline available for now. The main benefit for us the org provides is a shared permission model for contributions so that we don't have to bug @developit each time we make a PR to our offspring libraries like preact-router and preact-render-to-string.

Status: Bundle size

With this release we have surpassed the total bundle size of the 8.x line. Due to improved tree shaking the hello world example will be smaller though. Depending on how the future will unfold we may put more focus in the next weeks on finding ways to cut down on size :crossed_fingers: This is a lot easier to do with an extensive test suite like we have now :+1: Stay tuned!

Without further ado, here is the full changelog:

Bug Fixes

  • Keep track of childDom between diffChildren calls (#1515, thanks @andrewiggins)
  • Remove getFirstOldDom (-42 B) (#1531, thanks @andrewiggins)
  • Add support for arrays with holes as placeholders (#1440, thanks @marvinhagemeister)
  • Apply state updates based on depth (#1534, thanks @JoviDeCroock)
  • Fix incorrect depth ordering (#1536, thanks @marvinhagemeister)
  • Fix nodes with different keys being reused (#1532, thanks @marvinhagemeister)
  • Fix stale DOM with async preact-router (#1539, thanks @marvinhagemeister)
  • Fix Portals not being unmounted (#1537, thanks @marvinhagemeister)
  • act should be able to track and flush the full queue and all subsequent queues (#1520, thanks @JoviDeCroock)
  • Fix error with component attributes that start with on (#1530, thanks @JoviDeCroock)
  • Remove prop-types dependency (#1525, thanks @natevw)
  • Add clear button to demo logger (#1517, thanks @marvinhagemeister)
  • Add _depth to mangle.json (#1542, thanks @38elements)
  • Remove unnecessary code (#1543, thanks @38elements)


  • Use same type naming as @types/react (#1519, thanks @marvinhagemeister)

A bit quicker than usual, but we felt like the recent changes are worthy enough to be part of a dedicated release. Originally we planned to just include a fix for our prop-types validation in debug and when looking at our open PRs we couldn't resist to add those that were already done.

The awesome release name is brought to you by @jviide :sunglasses:

Ghosting DOM elements :ghost:

When setState/forceUpdate was called in a lifecycle other than componentDidUpdate we sometimes didn't clean up the previous DOM correctly. This lead to ghosting effects and was the last fix needed to get our new people demo fully working (it uses mobx and mobx-state-tree). We're happy to see this is resolved :+1:

JSX Typings 💯

One of the PRs we are really excited about was made by @just-boris: He moved our JSX types under a dedicated preact namespaces allowing our types and @types/react to coexists without any conflicts. This is big for anyone using TS and we can't thank him enough for his PR :tada:

Streamlined useEffect 🔢

We reworked our cleanup code for effects with this release. Before new effects are executed we cleanup all previous ones instead of cleaning and executing them one-by-one. This was confusing and the new behavior is much more obvious when writing effectful code.


As with our last releases we received numerous amazing reproductions and issues which allowed us to quickly spot a bug and fix it. We really appreciate the short feedback loop. Without it we wouldn't be able to improve Preact X as much as we can :+1:


  • warn about deprecated properties (#1511, thanks @JoviDeCroock)

Bug fixes:

  • effect execution and cleanup order (#1501, thanks @JoviDeCroock)
  • _dom being null whenever sCU returns false (#1484, thanks @marvinhagemeister)
  • debug message should not throw for undefined and null (#1505, thanks @JoviDeCroock)
  • Remove unused component import (#1508, thanks @marvinhagemeister)


  • move JSX namespace into preact one (#1448, thanks @just-boris)

It's time for another Preact X release :tada: The past weeks were very productive and we're very happy to have been able to improve Preact on many fronts.

mjs is no more :100: ✅

We are very happy to have removed our .mjs bundles and are back with standard .js files. This was a common error when trying out the alpha with webpack because the resolution for mjs files is different. We're very thankful for @lukeed who stepped up and created a workaround with a custom webpack plugin that we have been referring to. But we all knew that we wanted to correct that with our next release and make Preact work out of the box with webpack again. This release does just that and you can safely remove webpack-modules :+1:

Developer Experience Enhancements :hammer_and_wrench:

For this release we spent a few days working on improving the developer experience when writing Preact apps. For that we added more warnings to preact/debug which should catch some common issues you may have run into. These will be visible in your browsers console :tada:

  • Warn on double encoding of JSX literals and other invalid nodes passed to createElement/h
  • Warn when an event handler is not a function
  • Warn when the container node passed to render() doesn't exist in the DOM
  • Warn on invalid dependencies passed to useEffect/useLayoutEffect

Here is an example:


Other notable changes

Thanks to the stunningly beautiful "people demo" that @phaux contributed we were able to catch two issues when using Preact together with mobx-react. Our compat shim is now on a level where mobx-preact isn't needed anymore (it was lagging behind in terms of features compared to mobx-react).


What's next

We brought in the first batches of reconciler fixes but have a few pending changes left to do. These mainly include fixes that will make Fragment support rock solid and an enhancements to createContext. When these are stable we'll move forward to a beta release :+1: We even have some cool performance improvements in the pipeline 🤫

You all are amazing!

As always we'd like to take time to thank everyone who has filed issues or participated in discussion. The issues in particular are much higher quality than just a few months ago. We've received quite a few comments on twitter or in person from friends working on other OSS projects that they love our community and the positivity ours is known for. Just wanted to pass on the praise to you all :tada: :heart:

Without further ado, here is the full change set:


  • Add warnings for invalid useEffect/useLayoutEffect dependencies (#1495, thanks @JoviDeCroock)
  • Add warnings for useMemo/useCallback when dependencies haven't been specified (#1499, thanks @JoviDeCroock)
  • Add more createElement warnings in debug (#1494, thanks @marvinhagemeister)
  • Add warnings for render() (#1487, thanks @JoviDeCroock)
  • Add warning for invalid event handlers (#1409, thanks @JoviDeCroock)
  • Add teardown to test-utils (#1458, thanks @JoviDeCroock)
  • Add people demo from #1388 (#1453, thanks @andrewiggins @phaux)
  • Add back unstable_batchedUpdates and replace mobx-preact with mobx-react in demo app (#1477, thanks @marvinhagemeister)
  • Add support for CSS Grid (#1407, thanks @JoviDeCroock)
  • Switch from *.mjs -> *.module.js (#1425, thanks @marvinhagemeister)
  • Save 3 bytes (#1466, thanks @38elements)
  • Add teardown to test-utils (#1458, thanks @JoviDeCroock)

Bug Fixes

  • event.persist should be a function, not an object (#1498, thanks @JoviDeCroock)
  • Fix Portal crashing devtools (#1491, thanks @marvinhagemeister)
  • Fix stale DOM caused by empty Fragments (#1489, thanks @marvinhagemeister)
  • Add test for fragment ordering (#1478, thanks @JoviDeCroock)
  • Fix DOM removed before componentWillUnmount (#1471, thanks @marvinhagemeister)
  • Don't call setState callback or enqueue a render in constructor (#1454, thanks @JoviDeCroock)
  • Jump to the next childDom if its _dom is null (#1452, thanks @Almo7aya)
  • Apply compat normalisation for every vnode (#1450, thanks @JoviDeCroock)
  • Fix changes in getDerivedStateFromProps is not reflected to _nextState (#1446, thanks @mochiya98)
  • Fix missing mangle config for _prevState (#1442, thanks @mochiya98)
  • Always diff checked/value properties against the DOM. Fixes #1324. (#1438, thanks @utkarshkukreti) 🎉
  • Add missing test-utils export in preact/compat (#1436, thanks @JoviDeCroock)
  • Replace Object.assign with custom assign function (#1433, thanks @marvinhagemeister)
  • Don't iterate over old CSS string (#1429, thanks @marvinhagemeister)
  • Fix safari failing on calc with CSS Custom Properties in SauceLabs (#1428, thanks @marvinhagemeister)
  • Don't append px suffix for CSS Custom Properties (#1426, thanks @marvinhagemeister)
  • Updated links to the funcy.js source. (#1420, thanks @michael-klein)
  • Fix componentDidUpdate arguments (#1455, thanks @38elements)
  • Fix tagName prop trying to change element type (#1419, thanks @JoviDeCroock)
  • Fix missing className normalization on hydrate (#1421, thanks @marvinhagemeister)
  • Fix inconsistencies in act (#1437, thanks @JoviDeCroock)
  • Always diff checked/value properties against the DOM. (#1438, thanks @utkarshkukreti)
  • Render bailout on equal state transition (#1449, thanks @JoviDeCroock)
  • support svg attributes (#1451, thanks @JoviDeCroock)
  • Move context update logic to diffing (#1468, thanks @JoviDeCroock)
  • Fix remove button adding todos in demo app (#1488, thanks @marvinhagemeister)


  • Update option types (#1493, thanks @JoviDeCroock)
  • Update internal compat types (#1483, #1456, thanks @38elements)
  • Update internal context types (#1432, thanks @38elements)
  • Update Component in internal.d.ts (#1443, thanks @38elements)
  • Fix vnode type definition (#1447, thanks @38elements)
  • Remove unnecessary settings in tsconfig.json (#1457, thanks @38elements)

The weekend is coming and we thought it be a good time to make another alpha release for everyone to play with 🎉

This was a wonderful week for us. More and more bug reports contain links to a reproducible test case. You all are simply amazing! We wouldn't be able to fix this many bugs without all your help 👍 Even our contributions had an alltime high with excellent PRs from the community!

Despite fixing many bugs we landed a new package to help you test hooks in Preact 🎉

Introducing preact/test-utils

With hooks having their own scheduling logic, we didn't have a good testing story up until now! First-time contributor @JoviDeCroock went right into it and quickly had a prototype running. With the blink of an eye he had a PR that was ready to be merged. These testing utilities are inspired by the excellent react-dom/test-utils tools and share a similar act() function :+1:

For testing hooks effectively we need to flush pending effects synchronously. The brand new act() function allows you to do just that:

import { act } from "preact/test-utils";

let spy = sinon.spy();
function StateContainer() {
  return <div />;

// Wrap the render() with `act` to flush hooks automatically
act(() => render(<StateContainer />, document.body));

// Do your assertions 🎉

If you're working with class-based components you can use the new setupRerender function to flush pending state updates in your tests:

import { setupRerender, Component } from "preact/test-utils";

// Setup rerender logic first
const rerender = setupRerender();

let updateState;
class App extends Component {
  constructor() {
    this.state = { count: 0 };
    updateState = () => this.setState(prev => ({ count: ++prev.count }));

  render() {
    return <div>count: {this.state.count]}</div>;

// Render your component
render(<App />, dom);
expect(dom.textContent).to.equal("count: 0");

// Trigger a state update

// Flush all state updates

expect(dom.textContent).to.equal("count: 1");

It's his first contribution to Preact and we couldn't be more ecstatic about his work. Give him a round of applause 👍 It's also good to know for us that our code remains very accessible for new contributors.


  • Fix devtools not loading (#1360, thanks @calebeby)
  • Inline vnode children (#1317, thanks @developit)
  • Remove double Promise on initialization (#1370, thanks @bmeurer and @marvinhagemeister)
  • Fix camelCase style properties not working (#1375, thanks @mochiya98)
  • Fix Portal rendering undefined tags into the DOM (#1367, thanks @marvinhagemeister)
  • Fix this.props not set for PureComponent components (#1384, thanks @marvinhagemeister)
  • Use console.error for caught errors in the devtools adapter (#1385, thanks @yuqianma)
  • Fix state not updated when setState is called in componentWillReceiveProps (#1369, thanks @mochiya98)
  • Fix svg foreignObject not being treated as svg (#1391, thanks @marvinhagemeister)
  • Fix onBeforeInput not attaching event handler (#1366, thanks @marvinhagemeister)
  • Fix React.isValidElement check failing for vnodes created with Preact (#1380, thanks @marvinhagemeister)
  • Fix <select>.value not working (#1397, thanks @JoviDeCroock)
  • Fix multiple selections for <select> only selecting last item (#1405, thanks @JoviDeCroock)
  • Fix force flag blocking state update in second render() (#1377, thanks @developit)
  • Fix IE11 crashing because of missing Element.prototype.remove (#1395, thanks @marvinhagemeister)
  • Fix forwardRef and memo ignoring refs when composed together (#1358, thanks @marvinhagemeister)


  • Move _prevState for devtools out of core (#1379, thanks @developit)
  • Reuse oldChildrenLength to save bytes (#1386, thanks @yuqianma)
  • Don't call setProperty for style strings (#1394, thanks @choumx)


  • Fix unable to satisfy type parameters for static methods (#1365, thanks @marvinhagemeister)
  • Add back missing camelCase attributes (#1390, thanks @marvinhagemeister)
  • Add missing autocorrect attribute types (#1393, thanks @garybernhardt)
  • Ignore final new line for all mangle.json files (#1378, thanks @developit)
  • Add more tests for componentWillReceiveProps (#1387, thanks @developit)

Phew what an exciting few days it has been! We've been blown away by the wonderful responses to our 10.0.0-alpha.0 release and are excited to ship the next one with a good dozen of bug fixes.

In just three days we received a lot of awesome PRs pushing Preact X forward 👍 This wouldn't be possible with the outstanding issues we've received. They all had a link to a codesandbox where the issue could be easily reproduced. This is every maintainer's dream and we can't stress enough how much time it saves us to fix bugs 🚀

  • Switch away from MessageChannel to setTimeout + requestAnimationFrame 🎉 (#1346, thanks @cristianbote)
  • Fix lifecycle order of componentWillReceiveProps in relation to shouldComponentUpdate 💯(#1348, thanks @mochiya98)
  • Fix incorrect operator precedence in memo() 🎉 (#1347, thanks again @mochiya98)
  • Preserve devtools global hook 🔧 (#1333, thanks @developit)
  • Fix missing server.js in npm package (#1332, thanks @developit)
  • Fix incorrect this binding in setState callback (#1344, thanks @marvinhagemeister)
  • Fix stale props and state reference when shouldComponentUpdate returns false (#1351, thanks @marvinhagemeister)
  • Don't leak Text nodes out of toChildArray (#1357, thanks @developit)
  • Add missing consistent mangle name for _parentDOM (#1320, thanks @andrewiggins)
  • Add hgroup to TypeScript typings (#1340, thanks @ForsakenHarmony)
  • Add missing isReactComponent-property in preact/compat (#1337, thanks @marvinhagemeister)
  • Downgrade IE11 to run on Windows 7 in Saucelabs (#1319, thanks @marvinhagemeister)

Preact X Alpha 0 is here!

tl;dr: Preact X is the next major release which comes with a plethora of highly requested features like Fragments, componentDidCatch, createContext, hooks and many compatibility improvements with third-party libraries.

Fragments ✅

Fragments has been the most requested feature for Preact for a long time and we were very keen on bringing them into Preact! With Preact X they are now finally here 🎉 Use the new Fragment export in your components to render children elements inline with their parent, without an extra wrapping DOM element. For example:

import { render, Fragment } from "preact";

function Table() {
  return (
        <Columns />

function Columns() {
  return (

render(<Table />, document.body);

// Resulting DOM:

You can also return arrays from your components:

function Columns() {
  return [

Don't forget to add keys to Fragments if you create them in a loop:

function Glossary(props) {
  return (
      { => (
        // Without the `key`, Preact can't efficiently add,
        // remove, remove new elements as the list changes
        <Fragment key={}>

Fragments are a major new feature of Preact X that largely motivated the rewrite
from Preact 8. We could really use a lot of help testing and validating our
Fragment implementation. If you find something that doesn't seem right, we would
really appreciate reporting a minimally reproducible example to help us improve
our implementation and messaging around Fragments.

componentDidCatch ✅

We all wish errors wouldn't exists in Web-Apps but sometimes they do happen. With componentDidCatch all errors that happen inside render or another lifecycle method can be caught. This can be used to display user-friendly error messages, or write a log entry to an external service in case something goes wrong.

class Foo extends Component {
  state = { error: false };

  componentDidCatch(err) {
    this.setState({ error: true });

  render() {
    // If an error happens somewhere down the tree
    // we display a nice error message.
    if (this.state.error) {
      return <div class="error">Something went wrong...</div>;

    return <Bar />;

Because setting a fallback content in an error case is so common we made this even nicer by adding for getDerivedStateFromError which calls setState automatically under the hood.

class Foo extends Component {
  state = { error: false };

  static getDerivedStateFromError(err) {
    // return argument for setState
    return { error: true } 

  render() {
    // If an error happens somewhere down the tree
    // we display a nice error message.
    if (this.state.error) {
      return <div class="error">Whoops! This should not have happened</div>;

    return <Bar />;


Preact now supports Hooks. React has some phenomenal documentation on hooks that's worth a read, particularly if you're getting started with them for the first time. In Preact, you import hooks from preact/hooks. If you're using a recent version of most bundlers, any hook functions you don't use won't be included in your application.

Here's what hooks look like in Preact:

import { h, render } from 'preact';
import { useState } from 'preact/hooks';

function Counter() {
  const [count, setCount] = useState(0);
                            // ^ default state value
  return (
    <div class="counter">
      Current count: {count}
      <button onClick={() => setCount(count + 1}}> +1 </button>
      <button onClick={() => setCount(count - 1}}> -1 </button>

render(<Counter />, document.body);

createContext ✅

The createContext-API is a true successor for getChildContext(). Whereas getChildContext is fine when you're absolutely sure to never change a value, it falls apart as soon as a component in-between the provider and consumer blocks an update via shouldComponentUpdate when it returns false. With the new context API this problem is now a thing of the past. It is a true pub/sub solution to deliver updates deep down the tree.

import { createContext } from "preact";

const Theme = createContext("red");

function Button() {
  return <Theme.Consumer>
    {value => <button style={{ color: value }}>click</button>}

function App() {
  return <Theme.Provider value="blue">
    <Button />

CSS Custom Properties ✅

Sometimes it's the little things that make a huge difference. With the recent advancements in CSS you can leverage variables for styling:

function Foo(props) {
  return <div style={{ "--theme-color": "blue" }}>{props.children}</div>;

Devtools Adapter

To be able to support all the recent advancements in the excellent react-devtools extension we knew we had to redo our devtools adapter. In previous version we disguised Preact as React v15 to connect to them but this was getting more and more difficult with features added in later releases like the Profiler tab.

For Preact X we rewrote our adapter from scratch and can directly hook into our own renderer. This is a lot more straightforward for us and eases feature development greatly. It didn't take long for us to bring the Profiler into Preact 👍

Compat lives now in core

Although we were always keen on adding new features and pushing Preact
forward, the preact-compat package didn't receive as much love. Up until now
it has lived in a separate repository making it harder to introduce breaking

// Preact 8.x
import React from "preact-compat";

// Preact X
import React from "preact/compat";

New compat features

  • forwardRef
  • UNSTABLE_*-Lifecycle hooks
  • memo

Removing old React APIs

To make maintenance easier we dropped all legacy APIs that were available
in React versions prior to v16. This includes the DOM-Factories API,
createClass, string refs and a few more.

Breaking Changes

We were very careful to introduce as few breaking changes as possible. As a user
the most noticable change will be that props.children is not guaranteed to be
an array anymore. This change was necessary to be able to support rendering
components that return an array of children without wrapping them in a
root node. On top of that this fixes quite a few issues with third-party
components that expect props.children to be undefined when no children are
passed around.

The VNode shape has changed

We renamed/moved the following properties:

  • attributes -> props
  • nodeName -> type
  • children -> props.children

The children of a VNode are no longer guaranteed to be a flat array.
props.children could be undefined or it could be a nested array of children.
Pass props.children to the newly exported helper toChildArray to always get
an array back.

import { h, toChildArray } from "preact";

function MyComponent(props) {
	// Always convert props.children to an array
	const children = toChildArray(props.children);
	return <div>I have {children.length} child nodes</div>;

Note: toChildArray will flatten and remove non-renderables like null, undefined, true, and false from the children array.

setState no longer modifies state synchronously

In Preact X the state of a component will no longer be mutated synchronously.
This means that reading from this.state right after a setState call will
return the previous values. Instead you should use a callback function to
modify state that depends on the previous values.

this.state = { counter: 0 };

// Preact 8.x
this.setState({ counter: this.state.counter++ });

// Preact X
this.setState(prevState => {
	// Alternatively return `null` here to abort the state update
	return { counter: prevState.counter++ };

render() has changed

The root render function (the one you import from preact) has changed. It no
longer returns the newly created DOM element. Its return type is now void. We
made it simpler, by removing the third argument that was used to hydrate the
DOM. Use the hydrate function instead to hydrate a server rendered DOM tree.

When render is called multiple times on the same elements, the trees will be
merged together. It no longer just appends to the DOM. This change will be
very welcomed by new users as it was a frequeuent source confusion 🎉

import { render, hydrate } from "preact";

const root = document.getElementById("root");

// Render into the DOM
render(<div>foo</div>, root);
// calling `render` a second time will merge the trees like you would expect it to
render(<div>foo<span>bar</span></div>, root);

// Or use `hydrate` if you're making use of server side rendering
hydrate(<div>foo</div>, root);

preact/devtools is part of preact/debug

Our devtools adapter has been moved into our debug package and doesn't require a dedicated import statement anymore. The preact/debug package must be imported before preact to prevent our devtools integration to be overwritten by the default one supplied by the react-devtools extension.

Better support for Tree-Shaking

A lot has changed in the past years in the bundling space. Most bundlers now
offer excellent support for tree-shaking, where unused exports can be dropped
if they are not used. In the past we always exported an additional object as
the default export. But because of the nature of JavaScript it is very hard
to prove that an object property will never be used, they were never removed.

By removing the default export completely, only the code you need will
be included in the bunlde. The rest will be tree-shaken away.

// Preact 8.x
import preact from "preact";

// Preact X
import * as preact from "preact";

// Preferred: Named exports (works in 8.x and Preact X)
import { h, Component } from "preact";

Note: This change doesn't affect preact/compat. It still has both named and a default export to remain compatible with react.

Other breaking changes

  1. Falsy attributes values are no longer removed from the DOM. For some
    attributes (e.g. spellcheck) the values false and '' have different
    meaning so being able to render false is important
  2. The Component constructor no longer initializes state to an empty object. If
    state has not been previously set, it will be set to an empty object the first
    time the component is rendered, after the constructor has been called
  3. A falsy argument passed to setState will not enqueue an update. This change was made to support returning null from the updater function, which allows users to abort an update. If you just want to trigger an update and don't care about the state itself you can call it with an empty object setState({}).
  4. The toplevel rerender export has been removed.

Minor Changes

  1. render(null, container) no longer renders an empty text node but instead renders nothing
  2. We longer support a synchronous options.debounceRendering. The value of options.debounceRendering must asynchronously invoke the passed in callback. It is important that contributors to Preact can consistently reason about what calls to setState, etc. do, and when their effects will be applied. See the links below for some
    further reading on designing asynchronous APIs.

Known Issues

  • Nested Fragments lead to more DOM operations than necessary
  • Hooks state not visible inside the devtools panel
  • Fix a bug in 8.4 where nested preact.render() calls would cause an infinite loop when flushing the mount queue. (#1269, thanks @pl12133!)

The cat is out of the bag 🙌 We finally revealed on what we have in store
for the next major version of preact which will be called Preact X 🎉 To give
you a sneak peak of what will be included check out this talk over at this.javascript
video, slides.
It's hard to make an estimate right now on when it will be released, but rest
assured we are nearly done and are working on upgrading the ecosystem
(cli, router,...) to ensure a smooth release.

That said we very excited about recent community contributions. This release
contains some awesome performance enhancements brought to you by @lowaa and
@rpetrich. On top of that there are some minor bug fixes and a lots of
improvements to our typings.

Thank you so much for everyone involved 👍

  • Perf: Improve adding and removing large trees 🎉 (#1211, thanks @lowaa)
  • Drain render queue in a single micro task 🎉 (#1135, thanks @rpetrich)
  • Fix missing build when installing from git (#1251, thanks @garybernhardt)
  • Fix invalid ref invocation (#1235, thanks @developit)
  • Fix cloneElement test (#982, thanks @decadef20)
  • Reorganize and improve render unit tests (#1199, thanks @andrewiggins)
  • Improve componentDidUpdate tests (#1198, thanks @andrewiggins)

TypeScript Improvements!

  • Add onInvalid form event (#1221, thanks @namankheterpal)
  • Fix h() overloads (#1246, #1214, thanks @gpoit, @garybernhardt)
  • Fix AnyCompoent type (#1249, thanks @scurker)
  • Use proper type for key (#1248, thanks @wojtczal)
  • Add boolean as a component child (#1219, thanks @KasparEtter)
  • Add onError image event (#1209, thanks @jackmoore)
  • Add support for defaultProps (#1181, thanks @Alexendoo)
  • Fix cloneElement definition (#1197, thanks @hiddedejong)

Flow improvements!

  • Fix typings for [email protected] (#1230, thanks @ngyikp)
  • Refine options flow type (#1204, thanks @reyronald)

README Improvements!

  • Add Ultimate-Guitar (#1244, thanks @JiLiZART)
  • Add logo to README (#1243, thanks @reviewher)
  • Add section for [email protected] (#1212, thanks @38elements)
  • Remove duplicate project (#1192, thanks @stephenmathieson)
  • Fixes an issue in 8.3.0 where prevState (as passed to componentDidUpdate) pointed to the wrong interim state value when batching (#1186, thanks @carlhopf!)
  • TypeScript: Added ShadowRoot and DocumentFragment as parent option to render (thanks @cromefire!)

New Features!

🙌 We've added support for the new getDerivedStateFromProps() and getSnapshotBeforeUpdate() lifecycle hooks. (#1094 & #1112). A huge thank-you to @andrewiggins and @marvinhagemeister for their amazing work on this!


  • We're shipping .mjs now! (#1165, thanks @mathiasbynens for the nudge)
  • Fix an issue where setState() could mutate state in-place (#1170, thanks @Mitranim for the fix and @dandv for digging into the Apollo issue!)
  • spellcheck={false} is now set as an attribute (#1110, thanks @marvinhagemeister!)
  • Some code golfing to offset the new lifecycle methods (#1122, thanks @andrewiggins, @marvinhagemeister)
  • A little perf/size tweak for render callbacks (#1113, thanks @valotas)
  • Someone found dead code in Preact! awesome. (#890, thanks @MrErHu & @clarkdo)
  • We've dropped IE9 and IE10 from our SauceLabs tests (thanks @mkxml!)

    Note: Preact will continue to support these browsers (that is to say, continue to avoid relying on features they don't support), but recent updates to Mocha mean our tests don't run there. Special thanks to @mkxml, @andrewiggins, @k1r0s and @marvinhagemeister for working to improve the test suite in this release!

TypeScript Improvements!

  • Add support for specifying the types of a component's children (#1116, thanks @Alexendoo)
  • Add on*Capture event handler attributes and PointerEvents to the TS definitions (#1101 #1102, thanks @jakearchibald)
  • Improve render()'s return type (#1085, thanks @valotas)
  • Add controlsList attribute for media elements (#1134, thanks @wayou)

This release fixes an issue with our minification pipeline, which incorrectly mangled export declarations.

  • Don't mangle module exports #1077, thanks @marvinhagemeister
  • [ts] Add missing ref and key attribute #1051, thanks @andrewiggins
  • [ts] Add default parameter for Generic argument of VNode #1082, thanks @andrewiggins
  • [ts] Remove devtools module declaraction #1083, thanks @andrewiggins

We're happy to cut a new release and are excited about the much improved TypeScript defintions.

We love how much the community around preact has grown in the past months (18k stars!) and we'd like to thank everyone who was involved. Wether you've helped finding bugs, made code contributions or improved our documentation, this release wouldn't be possible without you. :tada:


  • [ts] Rewrite TypeScript defninitions and add support for strict mode
    • #1071, thanks @levrik
    • #1044 #1033 #1026, thanks @marvinhagemeister
    • #1037, thanks @k1r0s
    • #1027, thanks @wuweiweiwu
    • #869, thanks @niedzielski
    • #737, thanks @valotas
    • #695, thanks @jmrog
    • #1015, thanks @ovr
    • #1005, thanks @jrf0110
    • #1003, thanks @programbo
    • #990, thanks @timurista
    • #933, thanks @scurker
    • #943, thanks @andybons
  • Fix HMR sometimes throwing with preact-router #988, thanks @developit
  • Fix preact/debug failing to load in Webpack 3 + ES Modules (#924 #935, thanks @whitetrefoil)
  • Added null to paren union type of render (#937, thanks @nickytonline)
  • [debug]: Warn when passing incorrect arguments to render() (#885, thanks @markselby9)
  • [ts]: stateful component should be assignable to AnyComponent (#905, thanks @mike-north)
  • [ts]: add link preload "as" to HTMLAttributes type definition (#907, thanks @niedzielski)
  • [flow]: Fix flow types and render method issue (#868, thanks @sgrowe)
  • A more durable fix for the Babel preset recursion issue (thanks @rmacklin)

This release makes some tweaks to the newly released preact/debug.

  • Enhanced errors for preact/debug
  • Fixed issue where key warnings could be shown for components without keys
  • Fix missing donation message 🙈 (#834)

8.2.2 fixes a bunch of little issues encountered by those upgrading to 8.2.1 👍

  • Use explicit import paths in src for ES Modules compatibility (#792, thanks @slaskis)
  • Fix CLI donation message failing if npm is unavailable (#804, thanks @andrejsm)
  • Fix Babel attempting to use Preact's configuration (#825, thanks @rubenmoya)
  • Fix invalid sourcemap by updating Rollup (#800)
  • preact/debug: Support for attributes with no .toString() (#754, thanks @plusCubed)
  • preact/debug: Allow string refs when preact-compat is present (#807)
  • preact/debug: Fix error when preact-compat was not present
  • Bugfix: revert flushMounts() change to fix incorrect timing (#750)
  • We're now shipping an ES Modules build and are using Babel 6! (thanks @btd, @matthewp, @gpoitch)
  • preact/debug by @NekR: import it and get lovely warnings, errors & devtools integration!
  • Switch back to microtasks (via Promise#then) for async! (#708)
  • Fix unnecessary child reordering for certain cases (#717 - thanks @windyGex & @e1ectronic)
  • Fix attributes not being removed when diffing against SSR'd DOM (#677, @dmail)
  • Fixed Boolean and Number component render return values rendering <undefined> (#671, @dharFr)
  • Typescript Definition Improvements (#634, #641, #669, #730, #740)
  • Optimizations (#672, #696, #697)

As of 8.1.0, we're officially out of beta! If you were waiting to upgrade to Preact 8, now's the time.

💁 8.x included a few important backwards-incompatible changes, so we've put together a 8.0 migration guide to help. The guide includes "polyfills" you can use to restore 7.x functionality so your migration goes smoothly.

If you have any issues upgrading, including anything caused by this release, drop us a line!

This release resolves a few issues people have had when upgrading.

  • Remove object check before setting attributes (fixes custom toString, #401 - thanks @NekR!)
  • Cast boolean children to null for component props (fixes rc-animate, #629 - thanks @hassanbazzi!)
  • Call componentDidMount on children before componentDidUpdate on parent (#440, #506 - thanks @robertknight!)
  • Revert 8.0.0 behavior of throwing when encountering undefined components (#627)
    • preact/debug will be released shortly and does a much better job reporting stack traces!

🌈 Also worth noting, the linkstate module is now available.

Quick follow-up to 8.0.0

  • fixes an issue with preact-router (thanks @lukeed & @kbaxter!)
  • Fixes element removal regression in old IE (#625)

8.0.0 (beta)

It's here! 🌈

This release represents a huge step forward for Preact:

  • Significantly increased performance - in some cases by 30%.
  • Better compatibility - key for PFC's, class integrations, capturing events.
  • Fewer edge cases - goodbye to unnecessary mounts and DOM hierarchy errors.
  • Even smaller - Preact had been 3.9kb for a while - now it's 3.3kb (and headed for 2.9kb!)

💁 If you're looking to upgrade, be sure to read the quick guide.

Breaking Changes

  • Pure Functional Components now have backing instances. This means key now works perfectly on PFC's. It also means you could use state and lifecycle methods in Functional Components... (#163, #517, #536, #586, #474)
  • linkState() has been removed from Preact itself. It is being published as a standalone linkstate module shortly.
  • class and className no longer serialize Object values to Strings. Instead, use classnames (#401)
  • preact/aliases is no longer necessary. createElement() is now an alias of h() right out of the box!
  • DOM element recycling has been removed. It was a source of issues for many, and is no longer necessary for great performance thanks to diff optimizations that reduce the number of cases where elements are removed and re-added. (#544, #351, #461, #459, #503, #535, #562)
  • Undefined components references now throw rather than rendering <undefined> (#574)
  • No more Symbol. Instead of try to use Symbol.for('preactattr'), __preactattr_ is always used.
  • Render debouncing now uses setTimeout(0) instead of Promises. It's smaller, doesn't swallow rendering errors in Safari, and was already the fallback (#357)
  • The non-standard componentDidUnmount() lifecycle method is removed. Use componentWillUnmount().
  • onXxxxCapture is now supported for registering capturing event handlers.
  • Events like focus and blur are no longer automatically capturing by default.

Bugs Fixed

  • Hierarchy errors are a thing of the past (thanks to recycler and PFC rewrites) (#380, #391)
  • Fixed edge case that could cause children to be rendered out of order (#581, #603)
  • Unmount lifecycle is always fired when replacing a Component with an empty element (#538, #534)
  • ref functions attached to DOM nodes are no longer invoked for updates, only for mount/unmount.

Other Notable Changes

  • "holes" in JSX children are now preserved and used intelligently by the diff (#580, #540)
  • Re-rendering a compositional child with a different key prop now triggers a remount (#338)
  • JSX children passed to a Component are preserved rather than normalized (#551)
  • Preact no longer relies on the Text or Array constructors for type checks, instead relying on duck typing (#595, #530)
  • Ignore whitespace-only Text nodes during SSR hydration. SSR boot is now significantly faster than cold boot.

Here's the list of changes itemized by commit:

Just a small bugfix release - DevTools was throwing an exception if components didn't inherit from Component. Preact supports components not inheriting from Component, so we've fixed the DevTools to match 👍

⚛️ Preact 7.2.0 is now available as a regular release!

npm install --save preact

Bugs Squashed

  • Fix IE issues from 7.1 and update test cases (huge thanks to @mkxml for the hard work on this 🙇)
  • Fix TextNode duplication in IE (#430, thanks also to @mkxml)
  • Fix unnececssary diff when swapping from dangerouslySetInnerHTML to children (thanks @harish2704)
  • Fix issue in 7.x with <select> sometimes not applying value prop (#446)
  • Don't stringify true children, instead skip them (#468, thanks @jxodwyer)
  • Fix issue where unmount could be skipped on a top-level component (#493, discovered by @insin)
  • (DevTools Integration) Fix multiple root element issue

New Features

  • Use a shared empty Array for props.children when there are no children. Fixes simple shallow equality-based shouldComponentUpdate for leaf nodes 🎉
  • Remove instanceof SVGElement check in favor of duck typing. Fixes JSDOM compatibility and improves diff performance (#423, thanks @nhunzaker)
  • Better TypeScript Definitions: Component lifecycle methods, setState callback, etc
  • 10x performance boost for initial rendering (#416)
  • Fix edge case when swapping component root (#414)
  • Fix diff reflow when removing leading element (#394)
  • Check existence of firstChild before checking if it is a Text node
  • Performance optimization for element/tree removal
  • Re-add short-circuit for PFC's (fixes compositional PFC triggering constant recycling)
  • Fixed TypeScript definition signature for linkState (#427)
  • Add a whole bunch of explanatory comments to the diff engine 🎉


This release fixes an issue when hydrating from a static server-rendered DOM that could cause Preact to do far more work than it should have been doing. If you're doing SSR, check out this release for a massive performance boost.


7.x is currently in beta. It should be an entirely safe upgrade for most.

The reason it's a new major version is because Preact now ignores externally created DOM elements when rendering, unless performing hydration from a server-render (ie - the diff is initiated from a render() against an element that was not created by the DOM renderer).


  • Preliminary React DevTools support thanks to the amazing @robertknight! 🙇


  • Prevent against reassignment of the same value to TextNodes in Firefox (#368, thanks @zbinlin)
  • When swapping the base of a composed child component, update its parent's base reference (#349)
  • Prevent accidental duplicate recycling of elements when swapping a component's root element (#373, thanks @jakearchibald)

With 6.3.0, the children prop (on a VNode) is now always an Array, even if there are no children. This allows us to skip an existence check when plucking children within render:

// 6.2.1 & prior:
({ children }) => children && children[0];

// As of 6.3.0:
({ children }) => children[0];

This change is backwards compatible since previously an empty array was already being returned for no children in some cases. Now it's just more consistent! 🌈

Bugfix: Switch to using the render parent to determine if re-rendering starting from within an SVG, since the current element may not exist (eg: for a component).


  • Support for infinitely nested children!
  • Massive performance boost for h() (the hyperscript/jsx processor/reviver).
  • Tons of little performance optimizations
  • Allow components to not inherit from Component without caring
  • Add aliases.js and typings.json to the NPM package.

Public Changes

  • Rename Component._disableRendering to Component._disable to save a few bytes
  • Removed undocumented support for getInitialState() on classful components.

This has never been part of the API but was left in core in order to support preact-compat's use. It is now being moved into preact-compat. This allows preact to normalize class components that don't inherit from Component.


  • Fix regression in 6.1.0 where state changes in componentDidUpdate() resulted in synchronous re-renders
  • Fix issue where rendering an SVG element using the className prop (alias) would incorrectly assign className as an attribute. /cc @pl12133
  • Fix serializing class for SVG (test included) (#334)
  • Tons of little optimizations!
  • Don't skip empty values in extend() (and thus in setState()). Fixes #308.
  • Address ownership issue when rendering using reclaimed DOM. Fixes #297.
  • Fix issue where re-rendering an intermediary high order component could remove (or fail to add) the associated element.
  • When removing old props from the DOM, skip those with empty values.
  • Exclusively rely on DOM state when diffing value and checked props. Fixes #326.
  • Use strict equality when comparing attribute values against prop values. Fixes #327.
  • Upon initial entry into diff, check if the diff should start out in SVG mode. Fixes #331.
  • Fix prop cache reset triggering in the wrong case (affected performance)
  • Add typings path to package.json. Fixes #318.
  • Add support for single level of array children in h() (#313)
  • Move both className to class normalization and hashed class stringification out of h() and into the DOM renderer.
    • Tiny possible breakage here: if you were creating VNodes using className and expecting them to have attributes.class instead of attributes.className, that is no longer the case.
  • Fix <input list="id"> when datalist element is placed after the input in the DOM (Issue #294, thanks @vutran!)
  • Fix HMR issue caused by recycling of a re-used Component base. (Issue #295, thanks @katopz!)
  • Make 6.x the official latest release!
npm install --save [email protected]


  • Add support for SVG <foreignObject> (#278, thanks @amio!)
  • Add preact/aliases import: A copy of preact that includes a createElement() alias (#168/#274, thanks @ngasull!)
  • Switch to use event capturing for increased consistency with React (#266/#271, thanks @i-like-robots!)

Breaking Changes

  • Discard keyed nodes when diffing children instead of allowing them to be reused unkeyed
  • linkState() no longer falls back to components path lookups and no longer auto-invokes functions
    • These features were unused & poorly documented, and added extra weight
  • Remove default empty options.vnode hook
    • While this is technically a breaking change, very few people use this API
    • Simply perform an existence check on the previous hook prior to calling it

Bug Fixes

  • Fix and tests for regression in 5.7 that could cause nodes to be removed (related to #260/#277)
  • Fix initial render failing to reuse certain components when picking up from SSR (#260)
  • When swapping between Text, Comment and Element nodes, recycle whole orphaned trees
  • Prevent the recycler from collecting non-Element nodes 🐛
  • Switch back to the pre-5.7 case-sensitive on prefix for event handler props (#275, thanks @c2h5oh!)
  • Correct regression introduced in 5.6.0 where re-rendering components with the same root node could duplicate their DOM. Fixes #257.
  • Enforce this.props and this.context, even when a class improperly inherits from Component (eg: calls super() without forwarding arguments)
  • Fix for all empty vnodes ("", null, etc) rendering a comment - this should only occur when an empty vnode is returned from a component's render().
  • Make event handler "on" prefix case-insensitive


  • When rendering null, a comment node will be inserted instead of an empty TextNode.
  • When using linkState() with components instead of DOM elements, use the first argument passed to the event handler as the default value unless a path is given.

Bug Fixes

  • Fix case where switching from a String to Object style value would attempt to assign numeric CSS properties to the element (#233)
  • Fix bug where using all lowercase event names would skip bypass binding implementation (but still mostly work)
  • Fix and test for double-nulling of refs when changing the type of a component's root DOM element (#243)
  • Fix IE bug caused by assigning to the nodeValue property of a TextNode that has been removed from the DOM.
  • Fix this.base not being unset when unmounting High-Order components (#239)


  • #237 Imporving performance by inlining hook calls (thanks @trashhalo!)
  • Disable rendering on unmount (thanks @Madumo!) [discussion]

Bug Fixes

  • Fix keyed node removal issue noted by @localvoid and originally noticed by @kruczy in #235.
  • Fix for erroneously recycled components

🎉 Preact 5 is here! 🎈

Version 5 represents a fairly major jump forward. It should be backwards-compatible, but major version increment is to signify a few new features that will not be made available in older versions - mainly built-in SVG support, and async rendering.

Take a few seconds and upgrade, you'll be happy you did! 🌈

Tip: If you're using preact-compat, it's best to upgrade that to 2.0.0 at the same time. Since Preact 5+ now includes built-in support for SVG, [email protected] drops the preact-svg dependency, saving you around 1.7kb.

Along with the lovely stable stamp, this release includes some finishing touches:

Bug Fixes

  • Fix case where a ref may be nulled before a component is unmounted (#232, thanks @slmgc!)
  • Ensure remounting component trees invokes mount lifecycle events for deeply nested children (thanks to @kruczy @madumo et al for their help with this!)

New Features

  • Style objects now have a lightning fast pipeline out to the DOM. (#228, thanks @trashhalo!)

    <div style={{ foo:'bar '}} /> now diffs against the current style rather than stringifying the object

  • Fixed lifecycle event DOM timing! #65 and #96
  • Fixed swapping issue #230


  • #220 - Add Flow definition (fixes #219) - thanks @bouk!

Bug Fixes

  • #218 - Fix nested JSX text children resulting in multiple TextNodes (thanks @bardt!)

Minor Changes

  • Fix an inconsistency with how defaultProps are applied (developit/preact-compat#47)

    A key in props with a value of undefined should be treated as a missing key, and the value from defaultProps should be used in its place.

  • Switch setImmediate backend from MessageChannel to Promise#then (change diff)

    This is much faster!

    However: This comes with the caveat of being unusable for animation. While this matches the use-case for setImmediate() within Preact (debouncing rendering), it means that componentDidUpdate() and setState() callbacks should not be used as a means of animation. *

    * This is only true when using the built-in debounce mechanism. Overriding to requestAnimationFrame is still a great way to do animations via these hooks.

Bug Fixes

  • Fix an issue where swapping between functional and classful children of a high-order component could trigger an unmount in certain cases

    💁 If you're using preact-router, this fixes a redirect breakage

  • #207 Fix xlinkHref prop for <svg> tags - thanks @aeosynth!


  • Ignore props.children if children are manually specified (as jsx children, or the third argument to h())
  • Fix and test for the <svg class> bug @zhenkunou found and reported in #202
  • Tiny size optimizations to offset the cost of the above fix :)
  • Fix and (corrected) test for object style attribute serialization (#204) - thanks @katopz
  • 🎨 Add built-in support for inline SVG! (#202)


  • Fix issue where value and a few other properties could get out of sync with their DOM counterparts.
  • Fix overly optimistic codemod that was breaking child resolution in 5.0.1-beta.14. The codemod is now more intelligent and will only remove pointless initialization to undefined if not done within a conditionally executable block.
  • Fixes 5.0.1-beta.13 having been published without the beta flag.
  • Bugfix: When recycling old trees due to a Component render producing a different root node, avoid accidentally recycling the base of a high-order child component.

Bug Fixes

  • Fix issue where switching HOC child components could trigger unmount lifecycle methods on the parent

Bug Fixes

  • Fix issue where Components rendering null would break functional root check introduced in 5.0.0-beta9 (#182)
  • Fix clearing a previously null/undefined value when using className compat alias (#181)

New Features

  • Allow functions as VNode children (#154)

This is used in libraries that provide animation functionality by re-rendering function children with changing props:

render() {
  return (
    <SomeAnimator start={0} end={155} loop>
      { hue => (
        <span style={{ color: `hsl(${hue}, 100%, 60%)` }}>Rainbow</span>
      ) }

Bug Fixes

  • Account for High-Order stateful child components wrapped in one or more functional components (#175)
  • Fix disappearing element issue when swapping component root between Element and Text nodes (#176)
  • Verify nesting ownership when attempting to unmount High-Order components


  • Various performance and memory optimizations

New Features

  • Add support for cloneElement(). See React's Docs for more.

Bug Fixes

  • Wrap DOM property assignment in a try{} block, as it can throw.
  • Fix element reordering regression (#174)

Potentially Breaking Changes

  • Switch to exclusively named exports. Fixes compatibility with ES Module bundlers like Rollup (#150).

Bug Fixes

  • Don't invoke shouldComponentUpdate() when updating via forceUpdate() (#158)
  • Fix diff self-correction issue that resulted in an unnecessary element removal and re-append (#159)

Potentially Breaking Changes

  • DOM event handlers are no longer invoked with the source element as their context (this) (#153)
  • Adding properties to context within a tree no longer overwrites, instead it extends/appends (#156)

Bug Fixes

  • Fix for high-order component mount lifecycle (#143)
  • Fix incorrect rendering of 0 values (#149)


  • Add key property to VNodes (#155)


Preact 4:

Preact 5:

  • Fix children being ignored when passed explicitly via props in certain cases. Fixes developit/preact-compat#44 (thanks @ld0rman!)

    Fun fact: this means you can now do: <div children={['hello!']} />

  • Bugfix: Fixes an issue caught by preact-compat's ref tests, where swapping the root node rendered by a component would null its ref twice.
  • Fix regression in 4.6.2 related to recycled component DOM not being treated as first render
  • A few small optimizations
  • Merge #106: removes some unnecessary code, drops ~50 bytes

  • Lazy-instantiate the internal mapping for linkState() and setState's callback queue.

    This reduces allocation cost for components. It also reduces overall memory consumption for classful components that don't make use of those given features (certainly the common case for setState callback)

  • Don't attempt to append a child to a parentNode if the child is the parentNode. Fixes Issue #126.
  • Optimize serialization of Objects to CSS strings to be about 5x faster (benchmark:

  • Rethink solution to #120. TL;DR: fresh instances, cached DOM. Long version:

    Re-invoking the constructor on a class was not a great idea. Babel's transpiled constructors
    (and basically anything else) re-assign to the prototype, which is slow and a fairly bad idea.
    Also, and more importantly, it was assigning this.base to null, completely ignoring the
    main reason for caching components (caching their generated DOM using the component itself
    as a cache key). This commit changes the behavior to discard the cached component instance
    itself, re-using only the base by copying it to a fresh instance. Best of both worlds!

  • Fix for #122: don't assume Function.prototype exists, as it does not for Arrow Functions (thanks @LinusU!)
  • Fix regression since 4.5.0 where key tracking for components would fail in some cases, causing components not to be recycled. Relates to #98 and the second issue noted in #120.
  • Switch to a global/named symbol Symbol.for('preactattr') for the prop cache key (still falling back to __preactattr_).
  • Address the state re-use issue noted in Issue #120 by manually re-invoking component constructors when re-using components from the recycler.
  • Updated ESLint, announced website.

Bug Fixes

  • Fix context being null/undefined when unset. It should be an empty object.
  • Fix issue where ref (and key) were not being removed from props prior to being passed into component render (Issue #98)


  • Drop unnecessary cloning of props/context
  • Ship a more optimized default build by applying uglify-js without name mangling and with beautification (removes comments and applies dead code elimination)

Bug Fixes

  • When reclaiming externally created elements (such as via dangerouslySetInnerHTML), copy their attributes into the prop cache so they are properly diffed on subsequent render (Issue #97)
  • Fix cached unmount behavior: lifecycle events should be invoked for nested components, but only the top-level component should be physically removed from the DOM. The rest remain cached within that component's DOM + VDOM tree (Issue #94)
  • Fix exception thrown when removing/unsetting dangerouslySetInnerHTML
  • Fixed issue where setting the value prop for a <select> element could have no effect on initial render
  • Fix an issue where invoking refs may be skipped during unmount (ex: re-render swaps high-order components)
  • Fix a few cases where refs were invoked with the wrong value (Issue #87, thanks @chrisdavies)

Preact now explicitly removes falsey (false, null and undefined) properties and attributes from the DOM. This behaviour is consistent with React's. See #83 and #58.

  • Omit explicitly false JSX children to match the behavior of React (Issue #83).

This is purely a bug fix release, so be sure to update if you're using Preact 4.x.

Bugs Fixed:

  • Fix orphaned keyed VNodes not being removed in certain cases, such as when there are adjacent non-orphaned non-keyed VNodes (see developit/preact-compat#21)
  • When diffing a component against a non-component VNode, if the component render returns a different DOM node, make sure to reclaim the original node. (Issue #73)
  • Preact 4 is now officially out of beta. Please still report any bugs you find!
  • setState() callbacks should be called with the component as their context.
  • Fix multiple camelCase'd CSS properties (#66)
  • Fix child component refs not being invoked with null when the associated component is unmounted
  • Fix high order component refs linking to parent component when they should link to the child component/node.
  • Add support for refs!
  • Add support for defaultProps (static property on Components)
  • Possibly Breaking Change: cache rendered DOM with components when recycling
  • Possibly Breaking Change: don't wipe recycled DOM nodes, simply diff when re-used
  • Use setImmediate() to improve setState() performance where available
  • Skip empty values when serializing style objects
  • Coerce falsey className and style values to an empty string to avoid class="null" and style="null"
  • Rename missing component insert from <x-undefined-element> to <undefined>
  • Use a Symbol for storing the prop cache where available
  • Fix for key behaviour, and don't write keys to the DOM as attributes.
  • Performance tuning for a ~10% improvement on DBMonster (basically 10% faster diff algorithm)
  • Refactored diff algorithm to be easier to follow
  • Add Component.prototype.forceUpdate() method.
  • Fix a bug where a child component of a high-order component self-rendering (eg: via setState()) would cause a subsequent re-render of the parent component to re-initialize itself and the child (through the recycler, but this was causing thrash).
  • Fix an issue where nested components would not receive unmount lifecycle hooks (fixes Issue #47)
  • Bugfix: pass context through recycled constructors (with this react-redux is now fully supported!)
  • linkState() when used with top-level keys (ie, not dot-notated) will no longer mutate this.state in-place.

    (Nested keys can and will still mutate this.state, since the implementation of immutable state traversal would essentially be a small immutability library, not something Preact core can justify)

  • Performance tweaks!

This is likely the last beta release of Preact 3.0, it'll become the stable branch shortly.
Feedback and testing welcome!

  • Use a safeguard method to obtain preact attr cache objects before writes
  • Fix edge case where fallthrough attribute values would not be stored in the preact attr cache
  • null instead of delete for _component refs, avoiding shape mutations
  • build tweaks
  • Preact's codebase has been factored into modules
  • Reduced possible repaints by collecting property cache into a namespace
  • 10-20% performance improvement under heavy rendering load!
  • Now available in npm under a nice dist-tag: npm install [email protected]
  • Fixes for event removal (#34), tests.

Beta version of the 3.0.0 major bump:


  • Added context support
  • Bugfix: componentDidUpdate() should not be called after initial render
  • Switch from tracking nextState to tracking prevState
  • Drop VNode#__isVNode in favor of instanceof (reason)
  • Performance improvements for asymmetric DOM properties
  • Account for external mutation of properties
  • Fixes #5: props are now passed to Component constructors.
  • Fix: ensure the npm package includes src/ since it's now used by anyone using rollup for bundling (via jsnext:main).
  • Switch to a rollup-powered build, courtesty of @sheepsteak (thanks!)
  • Apply more strict linting around the codebase, removed some unused code. General cleanliness += 1.
  • Fix incorrect behavior where attributes with explicit false values were being skipped.
  • Readme updates as ever.
  • Fix componentWillMount / componentWillUnmount for high-order components
  • Fix detachment of content attributes by preferring their property equivalents where available

Re-add component.setProps() since other libs depend on it