Skip to content

Instantly share code, notes, and snippets.

@dferber90
Last active December 24, 2020 10:17
Show Gist options
  • Save dferber90/a7e636e6dfa0178c016ed488a6557273 to your computer and use it in GitHub Desktop.
Save dferber90/a7e636e6dfa0178c016ed488a6557273 to your computer and use it in GitHub Desktop.
React Caret Position Hook
// Usage example of useCaretPosition
// Shows a red caret when the cursor is at the end
import { useCaretPosition } from "./use-caret-position"
export function SomeComponent () {
const [value, setValue] = React.useState<string>("");
// actual usage
const inputRef = React.useRef<HTMLInputElement>(null);
const { selection, handleSelect } = useCaretPosition(inputRef);
// make caret red when it's at the end
const isCaretAtLastPosition =
selection.start === selection.end && selection.start === props.value.length;
return (
<input
ref={inputRef}
type="text"
value={props.value}
onSelect={handleSelect}
style={{
caretColor: isCaretAtLastPosition ? "red" : "inherit",
}}
/>
)
}
/**
* A React which returns the current caret position inside an input
*/
export function useCaretPosition<T extends HTMLInputElement>(
inputRef: React.RefObject<T>
) {
const [selection, setSelection] = React.useState<{
start: HTMLInputElement["selectionStart"];
end: HTMLInputElement["selectionEnd"];
direction: HTMLInputElement["selectionDirection"];
}>({
start: 0,
end: 0,
direction: "none",
});
React.useEffect(() => {
if (!inputRef.current) return;
setSelection({
start: inputRef.current.selectionStart || 0,
end: inputRef.current.selectionEnd || 0,
direction: inputRef.current.selectionDirection || "none",
});
}, []);
return {
selection,
handleSelect: (event: React.SyntheticEvent<T, Event>) => {
setSelection({
start: (event.target as T).selectionStart || 0,
end: (event.target as T).selectionEnd || 0,
direction: (event.target as T).selectionDirection || "none",
});
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment