ChatInput
먼저 보고, 그다음 계약을 읽습니다
Enter 전송·자동 높이 조절·툴바 슬롯을 갖춘 AI 채팅 입력창.
Component intent의도와 경계 읽기
uncontrolled <textarea> 를 감싼 forwardRef 컴포넌트로, 값은 내부 ref 로만 읽는다(defaultValue 로 초기화, onSubmit 은 trim 된 문자열을 넘긴 뒤 자동으로 비운다). Enter 로 전송하고 Shift+Enter 로 줄바꿈하며, 한국어 IME 조합 중(isComposing)에는 전송을 막는다. 입력에 따라 높이가 최대 240px 까지 자동으로 늘어난다(autosize). ref 는 DOM 이 아니라 ChatInputHandle({ focus(), clear() })을 노출해 외부에서 포커스·비우기를 명령형으로 제어한다. toolbarLeft/toolbarRight 슬롯으로 첨부·모드 선택·전송 버튼을 배치하고, 소비자가 넘긴 onKeyDown 이 preventDefault 하면 내부 Enter-to-send 를 건너뛰는 escape hatch 를 둔다.
예제
SSOT에 등록된 실제 API 기준 snippet입니다. standalone 배지만 독립 실행 단위이며, fragment는 주변 state·handler 문맥을 생략합니다.
import { ChatInput, Button } from "@axe/ui";import { useRef } from "react";import type { ChatInputHandle } from "@axe/ui";function Composer({ onSend }: { onSend: (text: string) => void }) { const ref = useRef<ChatInputHandle>(null); return ( <ChatInput ref={ref} onSubmit={onSend} toolbarRight={ <Button variant="primary" onClick={() => ref.current?.focus()}> 보내기 </Button> } /> );}<div class="axe-chat-input"> <textarea class="axe-chat-input__textarea" rows="1" aria-label="메시지 입력" placeholder="메시지를 입력하세요…"></textarea> <div class="axe-chat-input__toolbar"> <div><!-- toolbarLeft --></div> <div><span class="axe-chat-input__hint">↵ 보내기 · ⇧↵ 줄바꿈</span></div> </div></div>Props
TSX 소스가 진실입니다. 주요 export 컴포넌트의 public API만 노출합니다.
| 이름 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
placeholder | string | — | "메시지를 입력하세요…" | textarea placeholder — i18n 친화. |
onSubmit | (value: string) => void | — | — | 전송 트리거 — Enter(Shift+Enter 는 줄바꿈)와 외부 버튼 양쪽에서 호출. 빈 값(trim 후)은 전송하지 않으며 전송 후 입력이 비워진다. |
toolbarLeft | React.ReactNode | — | — | 툴바 좌측 슬롯 — 첨부·모드 선택 등. |
toolbarRight | React.ReactNode | — | — | 툴바 우측 슬롯 — 전송 버튼 등(없으면 hint 만 표시). |
hint | React.ReactNode | — | "↵ 보내기 · ⇧↵ 줄바꿈" | 툴바 우측 힌트 텍스트. false/null 이면 미표시. |
ref | React.Ref<ChatInputHandle> | — | — | DOM 이 아니라 명령형 핸들을 노출 — { focus(): void; clear(): void }. |
...rest | Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "onSubmit"> | — | — | defaultValue·aria-label·onKeyDown·onInput 등은 내부 textarea 로 전파(내부 핸들러와 체이닝). className 은 루트 .axe-chat-input 과 병합. |
.axe-* 클래스 계약
React 밖에서도 같은 표면을 그리는 공개 계약입니다. stable은 minor 버전 안에서 이름을 바꾸지 않습니다.
| 클래스 | 안정성 | 용도 |
|---|---|---|
.axe-chat-input | stable | 입력창 루트(세로 flex, 토큰 테두리/배경). :focus-within 에서 accent 테두리 + var(--ring). |
.axe-chat-input__textarea | stable | 실제 <textarea> — 테두리 0·투명 배경·resize:none, autosize 대상. |
.axe-chat-input__toolbar | stable | 하단 툴바 행(space-between 으로 좌/우 슬롯 배치). |
.axe-chat-input__hint | stable | 우측 힌트 텍스트(mono·tertiary·xs). |
접근성
키보드, ARIA, 구현 노트를 함께 검토합니다.
- Enter 로 전송(값이 비어있으면 무시)
- Shift+Enter 로 줄바꿈
- IME 조합 중 Enter 는 전송하지 않고 한글 확정에 사용
textarea 에 aria-label 을 넘기지 않으면 "메시지 입력" 으로 기본화. 그 외 role 은 네이티브 <textarea> 를 그대로 사용.
소비자 onKeyDown 이 먼저 호출되고, 그것이 preventDefault 하면 내부 Enter-to-send 를 건너뛴다(커스텀 키 처리용 escape hatch). onInput 은 항상 autosize 를 수행한 뒤 소비자 onInput 도 호출한다.