Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cursor jumps when backspacing in a number input (with ShadowDOM) #11827

Closed
YellowKirby opened this issue Dec 11, 2017 · 8 comments
Closed

Cursor jumps when backspacing in a number input (with ShadowDOM) #11827

YellowKirby opened this issue Dec 11, 2017 · 8 comments

Comments

@YellowKirby
Copy link

Do you want to request a feature or report a bug?
bug

What is the current behavior?
Number inputs with decimal values in Chrome ShadowDOM do not maintain cursor position as user backspaces in the input field.

Super low-quality gif (sorry):

This issue appears to be similar to the problem here: #7359, but in this case it's only custom elements with a shadow root that exhibit the problem.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template for React 16: https://jsfiddle.net/Luktwrdm/, template for React 15: https://jsfiddle.net/hmbg7e9w/).

  1. Have a React component render a number input: <input type="number" />.
  2. Attach that React component as part of the ShadowDOM node of a custom element.
  3. Enter in some decimal value (e.g., 88.88) into the input.
  4. Slowly backspace in the input. As soon as the decimal point would be the last character, the decimal point is removed and the cursor position jumps to the beginning of the input.

Demo: https://jsfiddle.net/69z2wepo/94566/

What is the expected behavior?

The ShadowDOM case behaves like the other cases: when backspacing in the input, the cursor does not jump to the beginning of the input and the decimal point is not unexpectedly deleted.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
React 16.2.0 + Chrome 62.0.3202.62 + OSX 10.12.6

@nhunzaker
Copy link
Contributor

nhunzaker commented Dec 11, 2017

Oooh boy :). I wonder if this is happening because this line here:

https://github.com/facebook/react/blob/master/packages/react-dom/src/client/ReactDOMFiberInput.js#L310

if (
    // Focused number inputs synchronize on blur. See ChangeEventPlugin.js
    type !== 'number' ||
    node.ownerDocument.activeElement !== node
) {

We only assign the value attribute on a number input if it isn't the currently focused element. This is designed to specifically avoid this issue because Chrome reformats number inputs (dropping decimal places) when you assign the value attribute to a number input.

This is to keep it as similar to other inputs as possible. I wonder if the input is never the active element in the case of a Shadow DOM.

@YellowKirby
Copy link
Author

I wonder if the input is never the active element in the case of a Shadow DOM.

Yeah, that activeElement line seemed a little suspect to me, but I haven't done much digging into the React codebase.

https://developers.google.com/web/fundamentals/web-components/shadowdom#focus has a simple function that will walk the shadowDOM in the case where activeElement does have a shadow root:

function deepActiveElement() {
  let a = document.activeElement;
  while (a && a.shadowRoot && a.shadowRoot.activeElement) {
    a = a.shadowRoot.activeElement;
  }
  return a;
}

@gaearon gaearon changed the title Cursor jumps when backspacing in a number input (+ ShadowDOM) Cursor jumps when backspacing in a number input (with ShadowDOM) Jan 2, 2018
@chrisdieckhaus
Copy link

chrisdieckhaus commented Jan 7, 2018

I'd be interested in taking a stab at this.

@avinashdvv
Copy link

avinashdvv commented Jan 14, 2018

Help
while i am tried to replicate this issue on my local mission with fixtures in https://github.com/facebook/react/ , i am getting an error like this
TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

code

import './polyfills';
import loadReact from './react-loader';

loadReact()
.then(() => import('./components/App'))
.then(App => {
	const {React, ReactDOM} = window;
	// ReactDOM.render(
	//   React.createElement(App.default),
	//   document.getElementById('root')
	// );
	class NumberInput extends React.PureComponent {
		constructor(props) {
		    super(props);
		    this.onChange = this.onChange.bind(this);
		    this.state = { value: '88.88' };
		}

		onChange(e) {
		    this.setState({ value: e.target.value });
		}

		render() {
		    return (
		       <label style={{display: 'block', margin: 10}}>
		         {this.props.children}:
		         {' '}
		         <input type='number' value={this.state.value} onChange={this.onChange} />
		       </label>
		    );
		}
	}

	// Broked :(
	customElements.define('with-shadow-dom', 
		class WithShadowDOM extends HTMLElement {
		   connectedCallback(){
				ReactDOM.render(
					<NumberInput>custom element with shadowDOM (broken)</NumberInput>, 
					this.attachShadow({ mode: 'open' })
		   )}
		}
	);

	ReactDOM.render(
		<NumberInput>non-custom element (working)</NumberInput>, 
		document.querySelector('#root')
	)
	document.body.appendChild(document.createElement('with-shadow-dom'));

});

@YellowKirby
Copy link
Author

@avinashdvv AFAIK that issue is happening because of the way babel typically transpiles ES6 classes. babel/babel#4480

You might need to add a plugin like https://github.com/WebReflection/babel-plugin-transform-builtin-classes in order for it to work correctly.

@OliverRadini
Copy link

OliverRadini commented Apr 1, 2021

Is this still known to be a problem? The fiddle mentioned in the original issue seems to work correctly now. I tried specifically setting the React version in the fiddle to 16.2.0 but it still works.

@YellowKirby
Copy link
Author

Hmm, yeah I can no longer reproduce either on the fiddle or when testing out some components on another project. Maybe this got fixed with an update to Chrome?

@matthewoates
Copy link

I can't reproduce this issue either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants