Autocompleteをカスタマイズする機会があり、少し詰まってしまったので
その時に使用したものをまとめてみました。
1. renderInput
Autocomplete のテキスト入力部分をカスタマイズする。
スタイルだけでなくイベントハンドリング(例:onChange
、onKeyDown
)も定義できる。
実装例
renderInput={(params) => (
<TextField
{...params}
onChange={(event) => setInputValue(event.target.value)}
onKeyDown={handleKeyDown}
/>
)}
2. renderOption
Autocompleteのドロップダウンリストの各オプションの表示方法をカスタマイズできる。
実装例
renderOption={(props, option) => (
<Box component="li" {...props}>
<Typography
sx={{
border: '1px solid #ccc',
borderRadius: '4px',
backgroundColor: 'lightBlue',
padding: '2px',
fontSize: '12px',
}}
>
{option.value}
</Typography>
</Box>
)}
3. filterOptions
ユーザーが入力したテキストに対して、候補リストに表示するオプションをどのように絞り込むかのロジックを定義できる。
例えば、部分一致や大文字・小文字の区別。
一致するものがない場合に新規オプションとして追加する処理などもここで実装した。
実装例
filterOptions={(optionsList, params) => {
const filtered = optionsList.filter((option) =>
option.value.toLowerCase().includes(params.inputValue.toLowerCase()),
)
if (params.inputValue.trim() !== '' && filtered.length === 0) {
const newOption: Option = {
id: params.inputValue,
value: `create: ${params.inputValue}`,
}
filtered.push(newOption)
}
return filtered
}}
4. renderTags
複数選択を有効にしている時に、選択したオプションのタグ表示をカスタマイズできる。
タグにCloseIconを仕込み、クリック時に選択を解除する機能などもここで対応する。
実装例
renderTags={(value, getTagProps) =>
value.map((option, index) => {
const tagProps = getTagProps({ index })
return (
<Box
{...tagProps}
key={option.id}
sx={{
display: 'flex',
backgroundColor: '#e3f2fd',
color: '#0d47a1',
borderRadius: '4px',
padding: '2px 4px',
alignItems: 'center',
fontSize: '12px',
}}
>
{option.value}
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation()
changeProperty(
category,
selectedValues.filter((v) => v !== option.value),
)
}}
sx={{ padding: 0, marginLeft: '4px' }}
>
<CloseIcon sx={{ fontSize: 12, color: '#0d47a1' }} />
</IconButton>
</Box>
)
})
}
5. slotProps
Autocomplete コンポーネント内部で利用されるサブコンポーネント(今回は候補リストを表示するためのポッパー)の表示位置や挙動(flip の無効化、オーバーフロー防止など)を制御する。
実装例
slotProps={{
popper: {
placement: 'top-start',
modifiers: [
{ name: 'flip', enabled: false },
{
name: 'preventOverflow',
options: {
altBoundary: true,
tether: false,
},
},
],
},
}}