Documentation
usePreserveInputCaretPosition

usePreserveInputCaretPosition

usePreserveInputCaretPosition tracks the input caret position and place it at the correct position so user can have a natural typing experience.

usePreserveInputCaretPosition won't return the caret position (selection range). If you want to track the selection range of an input, you can check out useSelectionRange.

Problem

Controlled Component (opens in a new tab) is a good way to have the fully control on the component of which the information is driven by the props instead of the local state.

Anyway, it has some caveats like when we have to format the input value (credit card, phone number, etc) whenever users enter one character. The caret will always be placed at the end of the value. And when users want to change a letter in the middle of the value, the caret will also jump right to the end.

This is annoying and it creates a bad experience for users.

💡

The example below will format the value to have the format xx-xx-xx.... Try to change a letter in the middle and you can see the caret will jump right to the end.

Install

To start using usePreserveInputCaretPosition, you can install the @react-awesome/use-preserve-input-caret-position library or you can import it directly from @react-awesome/components if you have installed it before. In your project directory, run the following command to install the dependencies:

npm i @react-awesome/use-preserve-input-caret-position

Usage

When using usePreserveInputCaretPosition the input now can perfectly handle the caret position. No more jumping to the end.

import { usePreserveInputCaretPosition } from '@react-awesome/use-preserve-input-caret-position'
 
export const Example = () => {
  const ref = useRef(null)
  const [value, setValue] = useState('')
 
  usePreserveInputCaretPosition(ref.current, {
    delimiters: ['-'],
  })
 
  const onChange = (e) => {
    if (!e.target.value) {
      setValue('')
      return
    }
    setValue(
      e.target.value
        .replace(/-/g, '')
        .match(/.{1,2}/g)
        .join('-'),
    )
  }
 
  return (
    <input ref={ref} value={value} onChange={onChange} placeholder="XX-XX-XX" />
  )
}

With Prefix

usePreserveInputCaretPosition also supports input has prefix.

import { usePreserveInputCaretPosition } from '@react-awesome/use-preserve-input-caret-position'
 
export const Example = () => {
  const ref = useRef(null)
  const [value, setValue] = useState('')
 
  usePreserveInputCaretPosition(ref.current, {
    delimiters: ['-'],
    prefix: 'PREFIX ',
  })
 
  const onChange = (e) => {
    // Example function to format the value with prefix
    setValue(formatWithPrefix(e.target.value))
  }
 
  return (
    <input ref={ref} value={value} onChange={onChange} placeholder="XX-XX-XX" />
  )
}

Paramaters

The usePreserveInputCaretPosition takes the following parameters:

inputEl

  • Type: HTMLInputElement

options

  • Type: UsePreserveInputCaretPositionOpts

Types

UsePreserveInputCaretPositionOpts

  • Type: object
prefix
  • Type: string
  • Default: undefined
delimiters
  • Type: string[]
  • Default: []