LoginSignup
10
9

More than 1 year has passed since last update.

React + MUI v5 でタグのようなUIを作る

Last updated at Posted at 2023-02-04

Gmail メール作成のアドレス表示のように、入力・選択した文字をタグ表示する方法です。React UIライブラリのMUIで作れると知り試作。共有したい方がいたので、この機会に調べた内容を残すことにしました。ご使用の際は、少しでも調査の時短につながれば嬉しいです。

試作品

スクリーンショット 2023-02-03 ゴール.png
離島名をタグ表示しました。
GitHub: rito-marker

環境

typescript: 4.9.5
react: 18.2.0
react-dom: 18.2.0
mui: 5.11.7

mui v5を使用するには次のバージョンが必要です
react: 17.0.0 以上
react-dom: 17.0.0 以上

公式情報

Peer dependencies
react >= 17.0.0 and react-dom >= 17.0.0 are peer dependencies.

方法

  1. MUIをインストール
  2. Autocompleteコンポーネントを使用
  3. タグのカラーを変更

1. MUIをインストール

npmの場合
npm install @mui/material @emotion/react @emotion/styled
yarnの場合
yarn add @mui/material @emotion/react @emotion/styled

2. Autocompleteコンポーネント

Autocompleteのデモ を参考にしました。必要なコンポーネントをインポートし、次のようにreturnします。

src/components/MarkerCreatingInputField.tsx
import { Autocomplete, TextField } from '@mui/material' //必要なコンポーネントをインポート

// ~~ 省略 ~~

return (

  // ~~ 省略 ~~

  <Autocomplete //importしたコンポーネントを使用
    multiple //複数選択できるようになる --- ①
    freeSolo //任意の入力値を管理できる(デフォルトはオプション選択のみ)
    filterSelectedOptions //選択されたオプションを非表示にする --- ②
    options={islands.map(option => option.name)} //ドロップダウンメニューの項目:文字列の配列
    value={inputValues} //入力欄に表示される値:①のときは文字列の配列、指定しないときは文字列 --- ③
    onChange={handleInputChange} //コールバック関数(オプションを選択か「Enter」を押すとイベントが起きる): function --- ④
    sx={{
      width: 600,
      display: 'inline-block',
    }}
    renderInput={params => (
      <TextField  //importしたコンポーネント
        {...params}
        variant='standard'
        label='離島マーカーを作る' // --- ⑤
        placeholder='離島名を選択か、入力後に「Enter」でタグが表示。「+」でマーカーを作成'
        error={validation.error} //エラー状態(trueのときは⑤labelや⑥helperTextが赤色になる): boolean
        helperText={validation.message} //入力欄の下に表示されるテキスト: node(公式のデモ通り文字列を指定) // --- ⑥
      />
    )}
  />
)

②の補足
選択されたオプションは非表示になります。
スクリーンショット 2023-02-03 選択前.png
スクリーンショット 2023-02-03 選択後.png
ですが、選択後に「+」ボタンでマーカーを作るようにしたので、その場合は再レンダー時にoptionsの配列で初期化され表示されます。そのため、マーカーを作成した離島は取り除きoptionsに含まないようにしました。

src/components/providers/ShapeMarkerProvider.tsx
  // Inputのセレクトオプション。textsにある離島名は削除し表示しない
  const islands = useMemo(
    () => ISLANDS.filter(island => texts.indexOf(island.name) === -1),
    [texts]
  )

④の補足
コールバック関数(handleInputChange)が受け取る主な引数は、function(event, value) です。なので入力した値はevent.target.valueではなくvalueで渡されます。また、multipleのときは文字列の配列で、指定しないときは文字列になります。このvalueを③のvalueへセットする流れになります。

3. タグのカラーを変更

今回はカラーを変更しませんでしたが、追加で調べました。2. AutocompleteデモのCodeSandboxを参考にrenderTags を追加します。図のようにChipコンポーネントを加え、例えばcolor='info'で画像のようにinfoカラーになります。今回はスタイル変更ではなくcolorを指定する簡単な例まででした。

src/components/MarkerCreatingInputField.tsx
import { Autocomplete, TextField, Chip } from '@mui/material' //Chipを追加

// ~~ 省略 ~~

<Autocomplete
  // ~~ 省略 ~~
  renderTags={(value: readonly string[], getTagProps) =>
    value.map((option: string, index: number) => (
      <Chip variant='outlined' label={option} color='info' {...getTagProps({ index })} /> //選択した離島名が各optionに渡される
    ))
  }
  // ~~ 省略 ~~
/>

スクリーンショット 2023-02-04 8.51.22.png
面白い名前の島があるんですね。ちなみに村役場さんの公式サイトを見ると、宝島は「海とサンゴと伝説に彩られたロマンの島」のようです:palm_tree:

参考

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9