Repository navigation
Maintenance: fix duplicated messages, autoscroll, React 18/19 and styled-components 6 support - #392
Merged
Merged
Conversation
The module-level singleton made every new Recognition return the first one, so a remounted or second ChatBot kept calling the callbacks of the first (possibly unmounted) component.
- A first user step was rendered as an empty bubble and immediately triggered the next step without waiting for the user. - Only read localStorage when cache is enabled and tolerate storage that throws (Safari private mode, quota exceeded). Ports #351.
… 18 tests - Move react/react-dom and lint tooling out of runtime dependencies - Widen peer ranges to react/react-dom >=16.3 and styled-components >=4 - Replace Travis/Node 8 CI with GitHub Actions on Node 20/22/24 - Stop tracking dist/ and coverage.lcov (dist is built on publish) - Fix flatted import path for flatted 3
Steps started their delay timer in componentDidMount and never cleared it, so React 18 StrictMode (mount, unmount, mount) triggered every step twice and the conversation doubled at each step. Custom components that called triggerNextStep more than once and double clicks on options had the same effect. - clear the step timer on unmount - let each step trigger the next step at most once - ignore repeated clicks on an options step
- Replace the removed DOMNodeInserted event with a MutationObserver, so the conversation scrolls to the last message again (Chrome 127+) - Don't restart speech recognition forever when it ends with no text - Don't access window when checking recognition support (SSR) - Copy options of update steps instead of changing the original step - Fix extraControl prop type (a single element, not an object of elements) - Use default parameters instead of defaultProps in icons (React 19)
styled-components 6 forwards every prop to DOM elements, which made React warn about user, isFirst, floating, opened, invalid and others. Filter the style-only props with shouldForwardProp; styled-components 4 and 5.0 ignore the option and keep filtering them as before. Tested with styled-components 4.4, 5.3 and 6.5.
rgba() returned null for named, rgb() or hsl() colors and the pulse animation threw. Fall back to color-mix() for those colors.
- Rebuild the step definitions when steps, avatars, delays or botName change, so steps that were not rendered yet use the new values - Select options without a value by their label (all of them matched the first option before) - Start the conversation from the parsed first step, so it gets the default settings too, and don't mutate the steps prop - Render DOM element components (e.g. <div />) without injecting step props, which React warned about - Don't speak cached steps again, and read speechSynthesis on every message so it can be toggled after mount - Ignore triggerNextStep calls with a value that matches no option
Autoscroll: - scroll to the bottom on every new message - for other DOM changes (loading bubbles, tooltips, ripples, content loaded inside custom steps) only scroll if the user didn't scroll up Accessibility (based on #293): - label the input, the submit/voice button and the open/close buttons - make the open/close buttons focusable and usable with the keyboard - use type="button" so the chatbot doesn't submit a surrounding form - use a valid input type and fix the invalid avatar width (40 -> 40px)
Types for the ChatBot props, every step kind, trigger/message functions, handleEnd and the props injected in custom step components. Checked in CI with tsc against tests/types.
The conversation used to run while the floating chatbot was still closed, so users opened it to find every message already there.
- LoadingStep leaked its delay prop to the DOM with styled-components 6 - The example uses createRoot and StrictMode and a real conversation (input, options without value and a custom step)
Also points the website and author links to the current domains (same change as #391).
- Build for ES5 (including flatted) so webpack 4 and older browsers can parse the bundle, as before - Stop tracking dist/ and build it in prepare, so installs from git get a fresh bundle - Remove engines, it would block installs on older Node versions
- Build steps again lazily, when a step is triggered, instead of on every parent render; keep the last valid steps if the new ones are invalid - Submit the recognized text when voice recognition ends (the batched speaking state restarted the recognition instead under createRoot) - Keep the value of a first custom step and evaluate its message on a copy, so looping back to it evaluates the message again - Restore option values from old caches - Don't focus the input of a closed floating chatbot - Allow boolean validators in the TypeScript declarations
Co-authored-by: vyk1 <[email protected]>
This was referenced Sep 26, 2026
Closed
Closed
Closed
This was referenced Sep 26, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Maintenance pass over the open issues and PRs: the toolchain works again on current Node, and the most reported bugs are fixed, each with a regression test.
Duplicated messages (React 18 StrictMode)
Steps started a timer in
componentDidMountand never cleared it. StrictMode mounts, unmounts and mounts again, so every step triggered twice and the conversation doubled at each step (1 → 2 → 4). Custom components that calledtriggerNextSteptwice, or double clicks on options, did the same.Fixes #346, fixes #370, fixes #350, fixes #386, fixes #278, fixes #202
Autoscroll
DOMNodeInsertedwas removed from Chrome (127+), which broke autoscroll there. It now uses aMutationObserver. A new message always scrolls to the bottom. Other DOM changes (tooltips, ripples, content loaded inside a custom step) only scroll if the user hasn't scrolled up.Fixes #380, fixes #133, fixes #232, fixes #321, fixes #288, fixes #266
Other bugs
window is not definedwhenrecognitionEnableis set. Fixes ReferenceError: window is not defined #377localStoragewas read even withcacheoff, which threw in Safari private mode. Ports get item from localStorage only when the cache is enabled #351. Fixes SetupBot not working in safari private window #296<div />), and React warned. Fixes React does not recognize thepreviousStepprop on a DOM element #261speechSynthesiscan now be toggled after mount. Fixes ENABLE/DISABLE SPEECH #248valueall selected the first option; they are now selected by their label. Fixes value should be defaulted to message (I can send you a PR if you want) #201extraControlhad the wrong prop type. Fixes extraControl is not working. I want to add extracontrol cutom button in the Footer #372Recognitionwas a module singleton, so a second or remounted chatbot kept the first one's callbacks.createRoot.userstep rendered an empty bubble and skipped the input.updatesteps changed the original step's options.Features
steps, the avatars, the delays andbotNameare used by steps that were not rendered yet. Fixes Add new step to existing step array #291, fixes message value not updated #301, fixes Not able to remove questions after bot answers them #349, fixes Dynamic 'Delay' for step #368, fixes How can I change the chatBot or userAvatar dynamically #221index.d.ts). Fixes I Need typescript Version of the Module! #340, fixes I Need typescript Version of the Module! #339type="button"so the chatbot doesn't submit a surrounding form. Fixes Accessibility in submit button #313Packaging and tooling
react,react-dom, prettier, eslint and onchange are no longer runtime dependencies. This removes the nested React 16 behind "Invalid hook call" and thebracesCVE. Supersedes Reinstalled packages for only development as dev-dependencies #328. Fixes Reinstall packages for only development as dev-dependencies #327, fixes Security: Vulnerable dependency 'braces' needs update to resolve CVE-2024-4068 #387react/react-dom >=16.3andstyled-components >=4. Tested with React 18 (full suite) and React 19 (createRoot suite), and with styled-components 4.4, 5.3 and 6.5. Style-only props no longer reach the DOM under styled-components 6. Fixes react-simple-chatbot is not installed on React v17.2.0 #305, fixes Issue between react-simple-chatbot and styled-components #381, fixes styled-components should be direct dep not peer dep #284, fixes Module not found: Can't resolve 'styled-components' in react-simple-chatbot/dist #300React,styled).dist/is no longer tracked. It is built byprepare, on publish and on installs from git.npm startworks again. Fixes Project is running at http://0.0.0.0:8080/ #389key).Test plan
npm run lint,npm run test:coverage(90 passing, 97% statements),npm run test:types,npm run buildnpm run test:domwith React 19.3