Command | CoUI

Command

검색 가능한 커맨드 팔레트 컴포넌트

Command#

키보드 중심의 커맨드 팔레트 컴포넌트입니다. 빠른 탐색, 검색, 액션 실행에 사용됩니다. CommandInput, CommandList, CommandGroup, CommandItem으로 구성됩니다.

Live Preview#

Web
Calendar
Search Emoji
Calculator
Flutter
Loading Flutter...
Command(
  items: [
    CommandItem(
      value: 'calendar',
      label: 'Calendar',
      icon: Icon(Icons.calendar_today),
    ),
    CommandItem(
      value: 'search',
      label: 'Search Emoji',
      icon: Icon(Icons.search),
    ),
  ],
  placeholder: 'Type a command or search...',
)
Command(
  items: [
    CommandItem(
      value: 'calendar',
      label: 'Calendar',
      icon: Icon(Icons.calendar_today),
    ),
    CommandItem(
      value: 'search',
      label: 'Search Emoji',
      icon: Icon(Icons.search),
    ),
  ],
  placeholder: 'Type a command or search...',
)

사용 시기 (When to Use)#

이 컴포넌트를 사용하세요:

  • 앱 전체의 기능이나 페이지를 빠르게 탐색하는 커맨드 팔레트가 필요할 때
  • 많은 수의 항목 중 키보드 입력으로 필터링하여 선택해야 할 때
  • 개발자 도구나 고급 사용자를 위한 단축키 중심 인터페이스를 구현할 때
  • 검색어 기반으로 그룹화된 액션 목록을 제공할 때

대신 다른 컴포넌트를 사용하세요:

  • Select: 정해진 목록에서 단순히 하나를 선택할 때
  • DropdownMenu: 컨텍스트 메뉴나 단순한 옵션 선택이 필요할 때
  • Input: 자유 입력 텍스트 필드만 필요할 때

기본 사용법 (Basic Usage)#

// 커맨드 팔레트 다이얼로그로 열기
showCommandDialog(
  context: context,
  builder: (context, query) async* {
    // 검색어 기반으로 동적 결과 반환
    final results = await searchCommands(query);
    yield [
      CommandCategory(
        title: Text('페이지'),
        children: [
          CommandItem(
            leading: Icon(Icons.home),
            title: Text('홈으로 이동'),
            onTap: handleNavigateHome,
          ),
          CommandItem(
            leading: Icon(Icons.settings),
            title: Text('설정'),
            onTap: handleNavigateSettings,
          ),
        ],
      ),
      CommandCategory(
        title: Text('액션'),
        children: [
          CommandItem(
            leading: Icon(Icons.add),
            title: Text('새 항목 만들기'),
            trailing: Text('Ctrl+N'),
            onTap: handleCreateNew,
          ),
        ],
      ),
    ];
  },
)
// 정적 항목 목록으로 커맨드 팔레트 구성
Command(
  placeholder: '명령어를 입력하세요...',
  onSelect: handleCommandSelect,
  items: [
    CommandItem(
      value: 'home',
      label: '홈으로 이동',
      icon: Icon(Icons.home),
    ),
    CommandItem(
      value: 'settings',
      label: '설정',
      icon: Icon(Icons.settings),
    ),
    CommandItem(
      value: 'new',
      label: '새 항목 만들기',
      shortcut: 'Ctrl+N',
    ),
  ],
)

Props / Parameters#

Command (Flutter) / Command (Web)#

속성타입기본값설명
commands List<CommandGroup> 필수 표시할 커맨드 그룹 목록
onSelect void Function(String value)? null 항목 선택 핸들러
placeholder String '검색...' 입력 필드 플레이스홀더
emptyMessage String '결과 없음' 검색 결과 없을 때 메시지
filter bool Function(String, String)? null 커스텀 필터 함수

CommandGroup#

속성타입기본값설명
labelString필수그룹 헤딩 텍스트
items List<CommandItem> 필수 그룹 내 항목 목록

CommandItem#

속성타입기본값설명
valueString필수항목 고유 식별자
labelString필수표시 텍스트
iconWidget?null항목 아이콘
shortcut String? null 키보드 단축키 표시
onSelect CoreVoidCallback? null 항목 선택 시 콜백
enabledbooltrue활성화 여부

하위 컴포넌트 (Sub-components)#

CommandInput#

검색어를 입력하는 입력 필드입니다. Command 내부에 자동으로 포함됩니다.

CommandList#

필터링된 항목 목록을 표시하는 영역입니다.

CommandGroup#

관련 항목들을 그룹으로 묶어 헤딩과 함께 표시합니다.

CommandItem#

선택 가능한 개별 커맨드 항목입니다.

동작 스펙 (Behavior)#

인터랙션#

  • 타이핑: 입력 즉시 실시간 퍼지(fuzzy) 검색으로 항목 필터링
  • 키보드 탐색: / 화살표로 항목 이동, Enter로 선택
  • 마우스 호버: 항목 하이라이트, 클릭으로 선택

상태 전환#

  • 입력창 포커스 → 목록 표시
  • 검색어 입력 → 실시간 필터링
  • 항목 선택 → onSelect 콜백 실행 → 닫기
  • 빈 결과 → emptyMessage 표시

애니메이션#

  • 목록 열기/닫기: 150ms fade + slide
  • 항목 하이라이트 전환: 즉시 (인스턴트)
  • 필터링 결과 변경: 100ms ease

사용 가이드라인 (Usage Guidelines)#

✅ Do#

Dialog와 함께 사용하여 전역 커맨드 팔레트 구현

// Ctrl+K 단축키로 커맨드 팔레트 열기
CouiDialog(
  isOpen: isCommandOpen,
  onClose: handleCloseCommand,
  child: CouiCommand(
    placeholder: '명령어 또는 페이지 검색...',
    commands: appCommands,
  ),
)

커맨드 팔레트는 일반적으로 전체 화면 오버레이로 표시되어 빠른 접근성을 제공합니다.


❌ Don't#

너무 많은 그룹과 항목을 평탄하게 나열 금지

// ❌ 그룹 없이 50개 항목을 모두 나열
CouiCommand(
  commands: [
    CommandGroup(
      label: '모든 항목',
      items: allFiftyItems,
    ),
  ],
)

그룹 없이 많은 항목을 나열하면 탐색이 어렵습니다. 관련 항목을 의미 있는 그룹으로 분류하세요.

✅ Do#

단축키를 shortcut prop으로 표시

CommandItem(
  value: 'save',
  label: '저장',
  icon: Icon(Icons.save),
  shortcut: 'Ctrl+S',
  onSelect: handleSave,
)

커맨드 팔레트에서 단축키를 보여주면 사용자가 점차 단축키를 익혀 생산성을 높일 수 있습니다.


❌ Don't#

파괴적인 액션을 확인 없이 즉시 실행 금지

// ❌ 삭제 액션을 바로 실행
CommandItem(
  value: 'delete-all',
  label: '모두 삭제',
  onSelect: handleDeleteAll, // 확인 없이 즉시 삭제
)

커맨드 팔레트에서 파괴적인 액션을 선택하면 실수로 실행될 수 있습니다. 확인 다이얼로그를 거치도록 구현하세요.

✅ Do#

자주 사용하는 명령어를 상단에 배치하세요.

CouiCommand(
  groups: [
    CommandGroup(
      heading: '최근 사용',
      items: recentCommands,  // 자주 쓰는 항목 우선
    ),
    CommandGroup(
      heading: '전체 명령어',
      items: allCommands,
    ),
  ],
)

사용 빈도 높은 명령어를 상단에 배치하면 사용자가 빠르게 접근하여 생산성을 높일 수 있습니다.


❌ Don't#

Command 팔레트를 일반 폼 입력으로 사용하지 마세요.

// ❌ Command를 단순 검색 입력으로 대체
CouiCommand(
  onSelect: handleSearchResult,  // 검색 전용으로만 사용
  groups: [CommandGroup(items: searchResults)],
)

Command 팔레트는 단축키(⌘K)로 접근하는 글로벌 액션 도구입니다. 단순 검색에는 Input 또는 AutoComplete를 사용하세요.

접근성 (Accessibility)#

키보드 인터랙션#

동작
/ 이전/다음 항목으로 이동
Enter선택된 항목 실행
Escape커맨드 팔레트 닫기
Tab다음 포커스 가능 요소로 이동

스크린 리더#

  • Flutter: Semantics 위젯으로 combobox 역할 전달, 활성 항목 상태 알림
  • Web: role="combobox", aria-expanded, aria-activedescendant 자동 적용

터치 타겟#

  • 각 CommandItem의 최소 높이: 48px

크로스 플랫폼 차이점 (Platform Differences)#

v3.0부터 기본 API (enabled, onChanged 등)가 통일되었습니다. 아래는 플랫폼 고유 차이점만 나열합니다.

항목FlutterWeb
클래스명CouiCommandCommand
검색 방식Dart 문자열 매칭JS 문자열 매칭
오버레이Overlay 위젯CSS position: fixed
  • Kbd: CommandItem의 shortcut 표시에 함께 사용
  • Dialog: 전역 커맨드 팔레트를 오버레이로 표시할 때 사용
  • Input: 단순 텍스트 검색만 필요할 때 대안

조합 예제#

// Command + Dialog + Kbd 조합으로 전역 커맨드 팔레트 구현
CouiDialog(
  isOpen: isOpen,
  onClose: handleClose,
  child: CouiCommand(
    placeholder: '명령어를 입력하세요...',
    commands: [
      CommandGroup(
        label: '최근 항목',
        items: recentItems.map((item) => CommandItem(
          value: item.id,
          label: item.title,
          icon: Icon(Icons.history),
          onSelect: () => handleNavigate(item.route),
        )).toList(),
      ),
      CommandGroup(
        label: '설정',
        items: [
          CommandItem(
            value: 'theme',
            label: '테마 변경',
            icon: Icon(Icons.palette),
            shortcut: 'Ctrl+T',
            onSelect: handleToggleTheme,
          ),
        ],
      ),
    ],
  ),
)