Search code examples
javascriptiosreactjsinputmobile-safari

On iOS React text/number input is stuck forcing user to enter in phone number


In my React/NextJS app, I have this simple input:

Components:

Search > SearchSelect > ExchangeInfo.tsx:

Search.tsx

<SearchSelect
  assets={assets}
  selected={selected}
  exchange={exchange}
  exchanges={exchanges}
  fetching={fetching}
  aggregate={aggregate}
  checkAggregate={this.handleCheckAggregate}
  enterPosition={this.handleEnterPosition}
  exchangeSelect={this.handleExchangeSelect}
/>

//... the function:

@bind
handleEnterPosition(position: number) {
  this.setState({ position })
}

SearchSelect

<SearchExchanges
  selected={selected}
  exchange={exchange}
  exchanges={exchanges}
  checkAggregate={checkAggregate}
  aggregate={aggregate}
  enterPosition={this.props.enterPosition}
  exchangeSelect={this.props.exchangeSelect}
/>

ExchangeInfo

import React from 'react'
import { bind } from 'decko'

import { IAsset, IMarketAsset } from '../../shared/types'
import { EnterPositionStyle } from '../../styles'

interface IPropsInfo {
  asset: IAsset
}

interface IPropsCount {
  exchanges: IMarketAsset[]
}

interface IPropsPosition {
  asset: IAsset
  enterPosition(position: number): void
}

export const ExchangeSelectInfo = (props: IPropsInfo) =>
  <h2>Exchanges with <span>{props.asset.currency}</span> denominated in BTC, ETH, USD, USDC, or USDT will be listed above. Otherwise the asset's price will be an aggregate of supported exchanges.</h2>

export const ExchangesCount = (props: IPropsCount) => {
  const { exchanges } = props
  const pural = exchanges.length > 1 && 's'
  return (<option key={'default'}>({exchanges.length}) Exchange{pural}:</option>)
}

export class EnterPosition extends React.Component<IPropsPosition> {
  render() {
    const { asset } = this.props
    return (
      <EnterPositionStyle>
        <h2>Enter your <span>{asset.currency}</span> position in order to add asset to your Portfolio. Or add the asset to your Watchlist.</h2>
        <input type="number" placeholder="Enter Position" onChange={this.handleChange} />
      </EnterPositionStyle>
    )
  }

  @bind
  private handleChange(event: React.FormEvent<HTMLInputElement>) {
    const target = event.target as HTMLInputElement
    const parsed = parseFloat(target.value)
    const position = Number.isNaN(parsed) ? 0 : parsed
    console.log('target.value', target.value);
    this.props.enterPosition(position)
  }
}

It works on the web fine: https://moon.holdings (Or https://dev.moon.holdings) (Click on the + select an asset, then Aggregate then try to enter in position.

However on mobile it only lets me put in an actual phone number, and typing does not change the input :(

UPDATE

Seems that it's an iPhone issue, my Android friends can add in positions, but not my iPhone ones. Strange....

UPDATE

I added an input to the root component / container and it works... seems like the problem is that the input I'm using is embedded 3 components down. Or something related to that.

enter image description here

enter image description here

enter image description here


Solution

  • Believe it or not, this is a css problem. Saw your page, you have these css on inputs that cause problem in safari.

    user-select: none;
    -webkit-user-select: none;
    

    Remove them, and your inputs will get back to work. In case you have difficulty removing them, override with

    -webkit-user-select: text;
    user-select: text;