✏️

はみ出る文字をいい感じにする Input

2022/08/20に公開

こんにちは。
編集ボタンを押したら編集できて、それ以外はテキストを表示するだけのフィールドを作ろうとしたところ、いい感じのフィールドができたので作り方のメモ。「編集ボタンを押したら編集できて、それ以外はテキストを表示するだけのフィールド」というのは、以下の gif のようなフィールドです。

編集と表示の切り替え方法

切り替えにはinputreadonly用いています。デフォルトの属性の切り替えだけでできるので、実装もとても簡単です。

export const TextField = (props: { isEdit: boolean }) => {
  const ref = useRef() as React.MutableRefObject<HTMLInputElement>
  
  useEffect(() => {
    // 編集ボタン押下時にフィールドにフォーカスさせる
    if (props.isEdit) ref.current.focus()
  }, [props.isEdit])
  
  return (
    <input 
      ref={ref}
      readOnly={!props.isEdit}
    />
  )
}

考えられる不便な点

ただ、この実装では少し懸念点があります。
それは文字がフィールドをはみ出た場合に、ユーザーが見落としやすい点です。以下の画像は、ユーザーがフィールドいっぱいに文字を入力して保存した時の図です。フィールドの端まで hello で埋め尽くされていますね。

しかし、このフィールドの末尾は hello ではなく、goodbye でした。
上の画像を見ただけでは、「まだ続く文字がある」という認識がしづらく、見落としてしまう可能性があります。

不便さを解消する方法

このような事態を防ぎやすくする手法として、cssではtext-overflowというプロパティがあります。このプロパティは、テキストが範囲外まで表示される場合どのように表示するのかを定義できるプロパティですが、これは普通のテキストにはもちろん、inputの readonly 時にも適用することができます。
デモはこちらから確認できますが、今回利用したいのはellipsisという設定値です。これを設定することで、範囲外にはみ出る文字を「...」という表示にすることができます。

実装は以下のようにすると実現することができます。(styled-componentsを利用しています)

const Input = styled.input<{
  background?: string
  isEllipse?: boolean
}>`
  ${(props) => (props.background 
      ? `background: ${props.background};` 
      : '')}
  ${(props) =>
    props.isEllipsis
      ? `
      text-overflow: ellipsis;
      overflow-x: hidden;
    `
      : ''}
`

export const TextField = (props: { isEdit: boolean }) => {
  const ref = useRef() as React.MutableRefObject<HTMLInputElement>
  
  useEffect(() => {
    // 編集ボタン押下時にフィールドにフォーカスさせる
    if (props.isEdit) ref.current.focus()
  }, [props.isEdit])
  
  return (
    <Input 
      ref={ref}
      background={props.isEdit ? 'gray' : 'transparent'}
      readOnly={!props.isEdit}
      isEllipse={!props.isEdit}
    />
  )
}

この実装におけるユーザーに優しそうな点

inputにおけるtext-overflow: ellipseの嬉しい点は、テキストをフォーカスすると ellipse が解除され、フィールドの値を確認できる点です。
下の gif のように、readonlyinputに対してフォーカスすると、設定されているtext-overflow: ellipseが解除され、フィールドの中身を確認できるようになります。通常のテキストでは少し工夫をして実装(テキストにフォーカスされたら、cssを書き換えるなど)しないとできないと思いますが、inputについてはデフォルトの挙動で実現することができます。

ユーザーからすると、以下のようなメリットがありそうです。

1 「このフィールドには見えない値がある」という認識がしやすくなる
2. フォーカスすることで、編集ボタンを押下せずとも中身が確認できる利便性を保つことができる

終わりに

フィールド関連のコンポーネントは、ユーザーがほぼ必ず触れるコンポーネントになると思うので、より考えることが多いなあと思いました。今回のような実装をせずとも「フィールドにテキストの入力でき、編集と表示を切り替えられる」という機能自体は実現できますが、ひと工夫を入れることでより使いやすいコンポーネントになれる可能性があるとも感じました。(使いにくくなる可能性もありますが。。)

Discussion