F-002 Form medium

How to create a custom select dropdown カスタムセレクトの作り方

Fully styleable custom select box with animated dropdown options. スタイリング可能なカスタムセレクトボックス。アニメーション付きのドロップダウン。

ライブデモ Live Demo

カテゴリを選択 Select a category
Motion / Visual
Navigation
Layout / Structure
State / Loading
Theme / Behavior
Form / Input

概要・用途・特徴Overview, Usage & Features

何ができるかWhat it does

Fully styleable custom select box with animated dropdown options.

スタイリング可能なカスタムセレクトボックス。アニメーション付きのドロップダウン。

どこで使うかWhere to use

contact form, signup flow, checkout form, search interface

フォームフィールド、フィルターコントロール、ソートセレクター、言語セレクター

特徴Key features

Fully styled custom select dropdown replacing the native <select>. Animated chevron rotation on open. Keyboard navigable (arrow keys, Enter, Escape, type-to-search). Accessible with ARIA listbox pattern.

ネイティブ<select>を置き換えるフルスタイルのカスタムセレクトドロップダウン。オープン時にシェブロンが回転アニメーション。キーボードナビゲーション(矢印キー・Enter・Escape・タイプで検索)。ARIAリストボックスパターンでアクセシブル。

調整可能パラメータ Adjustable Parameters

Parameter Default Description
--select-radiusCorner radius size
--transition-speedOpen/close animation speed

実装コード Implementation Code

// react/F-002.jsx
import { useState, useRef, useEffect } from 'react';
import './F-002.css';

export default function CustomSelect({ options = [], placeholder = '選択してください' }) {
  const [open, setOpen] = useState(false);
  const [selected, setSelected] = useState(null);
  const ref = useRef(null);

  useEffect(() => {
    const handler = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); };
    document.addEventListener('click', handler);
    return () => document.removeEventListener('click', handler);
  }, []);

  return (
    <div className={`custom-select ${open ? 'open' : ''}`} ref={ref}>
      <div className="custom-select__trigger" onClick={() => setOpen(!open)}>
        <span>{selected || placeholder}</span>
        <span className="arrow" />
      </div>
      <div className="custom-select__options">
        {options.map(opt => (
          <div key={opt.value} className={`custom-select__option ${selected === opt.label ? 'selected' : ''}`}
            onClick={() => { setSelected(opt.label); setOpen(false); }}>
            {opt.label}
          </div>
        ))}
      </div>
    </div>
  );
}
/* react/F-002.css */
/* F-002: Custom Select Dropdown */
.custom-select {
  position: relative;
  cursor: pointer;
}

.custom-select__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border: 2px solid var(--border, #e0e4f0);
  border-radius: 12px;
  font-size: 16px;
  transition: border-color 0.3s ease;
}

.custom-select.open .custom-select__trigger {
  border-color: #5c6ac4;
  border-radius: 12px 12px 0 0;
}

.custom-select__trigger .arrow {
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid #999;
  transition: transform 0.3s ease;
}

.custom-select.open .arrow {
  transform: rotate(180deg);
}

.custom-select__options {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  border: 2px solid #5c6ac4;
  border-top: none;
  border-radius: 0 0 12px 12px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
  z-index: 10;
  background: #fff;
}

.custom-select.open .custom-select__options {
  max-height: 300px;
}

.custom-select__option {
  padding: 12px 16px;
  cursor: pointer;
  transition: background 0.2s ease;
}

.custom-select__option:hover {
  background: #f5f7ff;
}

.custom-select__option.selected {
  background: #5c6ac4;
  color: #fff;
}
import { useState, useRef, useEffect } from 'react';
import './F-002.css';

export default function CustomSelect({ options = [], placeholder = '選択してください' }) {
  const [open, setOpen] = useState(false);
  const [selected, setSelected] = useState(null);
  const ref = useRef(null);

  useEffect(() => {
    const handler = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); };
    document.addEventListener('click', handler);
    return () => document.removeEventListener('click', handler);
  }, []);

  return (
    <div className={`custom-select ${open ? 'open' : ''}`} ref={ref}>
      <div className="custom-select__trigger" onClick={() => setOpen(!open)}>
        <span>{selected || placeholder}</span>
        <span className="arrow" />
      </div>
      <div className="custom-select__options">
        {options.map(opt => (
          <div key={opt.value} className={`custom-select__option ${selected === opt.label ? 'selected' : ''}`}
            onClick={() => { setSelected(opt.label); setOpen(false); }}>
            {opt.label}
          </div>
        ))}
      </div>
    </div>
  );
}
/* F-002: Custom Select Dropdown */
.custom-select {
  position: relative;
  cursor: pointer;
}

.custom-select__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border: 2px solid var(--border, #e0e4f0);
  border-radius: 12px;
  font-size: 16px;
  transition: border-color 0.3s ease;
}

.custom-select.open .custom-select__trigger {
  border-color: #5c6ac4;
  border-radius: 12px 12px 0 0;
}

.custom-select__trigger .arrow {
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid #999;
  transition: transform 0.3s ease;
}

.custom-select.open .arrow {
  transform: rotate(180deg);
}

.custom-select__options {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  border: 2px solid #5c6ac4;
  border-top: none;
  border-radius: 0 0 12px 12px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
  z-index: 10;
  background: #fff;
}

.custom-select.open .custom-select__options {
  max-height: 300px;
}

.custom-select__option {
  padding: 12px 16px;
  cursor: pointer;
  transition: background 0.2s ease;
}

.custom-select__option:hover {
  background: #f5f7ff;
}

.custom-select__option.selected {
  background: #5c6ac4;
  color: #fff;
}

仕組みとカスタマイズHow It Works & Customization

仕組みHow it works

A visually hidden native <select> keeps actual form submission working. A visible custom trigger button and dropdown div are styled independently. JavaScript syncs their state: clicking the trigger opens the custom dropdown, selecting an option updates both the visible display and the hidden <select> value, ensuring form submission sends the correct value.

視覚的に非表示のネイティブ<select>が実際のフォーム送信を機能させます。可視のカスタムトリガーボタンとドロップダウンdivは独立してスタイリング。JavaScriptが状態を同期:トリガーのクリックでカスタムドロップダウンが開き、オプションの選択が可視表示と非表示の<select>値の両方を更新してフォーム送信が正しい値を送信することを保証。

カスタマイズ方法Customization

Add option grouping with <optgroup>-style category headings. Add a search input inside the dropdown for long lists (type-ahead filter). Support multi-select with checkboxes inside the dropdown options.

<optgroup>スタイルのカテゴリ見出しでオプショングループを追加。長いリスト向けにドロップダウン内に検索入力を追加(タイプアヘッドフィルター)。ドロップダウンオプション内のチェックボックスで複数選択をサポート。

注意点Caveats

Custom selects are complex to make fully accessible. Consider using the native <select> with CSS appearance: none and a custom arrow icon for simpler use cases. If building custom, follow the ARIA Listbox pattern strictly with role="listbox", role="option", aria-selected.

カスタムセレクトを完全にアクセシブルにするのは複雑です。シンプルなユースケースにはCSS appearance:noneとカスタム矢印アイコンを使用したネイティブ<select>の使用を検討してください。カスタムを構築する場合は、role="listbox"・role="option"・aria-selectedを使用してARIAリストボックスパターンに厳密に従ってください。

よくある質問 Frequently Asked Questions

How to customize the custom select dropdown? Custom Select Dropdownをカスタマイズするには?

Modify the CSS custom properties and class styles defined in the code section. Key adjustable values include colors, sizes, durations, and spacing. See the Adjustable Parameters section for specific variables.

コードセクションで定義されているCSSカスタムプロパティとクラススタイルを変更してください。色、サイズ、時間、間隔が主な調整可能値です。具体的な変数は調整可能パラメータセクションを参照してください。

How to use the custom select dropdown in React? ReactでCustom Select Dropdownを使うには?

Import the provided React component and its CSS file. The component accepts props for customization. Check the React code section for the full implementation and available props.

提供されているReactコンポーネントとCSSファイルをインポートしてください。コンポーネントのpropsでカスタマイズできます。完全な実装と利用可能なpropsはReactコードセクションを参照してください。

What are the performance implications of custom select dropdown? Custom Select Dropdownのパフォーマンスへの影響は?

This implementation uses CSS transforms and opacity for animations, which are GPU-accelerated. It's lightweight and doesn't cause layout thrashing. Consider using prefers-reduced-motion for accessibility.

この実装はCSSのtransformとopacityを使用しており、GPUアクセラレーションされます。軽量でレイアウトスラッシングを引き起こしません。アクセシビリティのためにprefers-reduced-motionの使用を検討してください。

AIへの指示テンプレート AI Prompt Template

以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.