Groo Design

Textarea

여러 줄 글을 받는 입력칸. 메모 본문 · 휴가 사유 · 설명 · 탈퇴 사유처럼 길게 쓰는 값을 받고, 쓴 만큼 높이가 자란다. 한 줄 값은 Input이다.

구조는 당근 SEED Textarea(Apache-2.0)를 따른다 — 상자(Container)와 입력. 상자 · 테두리 · 상태는 Input 의 상자형(outline)과 같고, 다른 것은 높이 · 위아래 여백 · 자라는 방식이다. 라벨 · 설명 · 오류 · 글자 수는 Field가 둘레에서 그린다. SEED 와 다른 자리는 맨 아래 "SEED 와 다른 점" 에 적었다(2026-10-01 사용자 결정).

수치 원본은 textarea.yaml이다. 수치 표 자리([표: …])와 그림 자리([그림: …])는 사이트가 그 파일로 그린다 — GitHub 에서는 그 파일 · 그림 코드로 가는 링크로 보인다.

9:41
거래 수정
점심 식사
팀 점심 — 다음 달 회식비에서 정산하기로 했다. 영수증은 사진으로 올려 둠.
46/100
9:41
메모
10월 회의록 - 디자인 시스템 입력칸을 SEED 로 - 고르는 칸은 다음 차례에 - 앱 적용은 컴포넌트를 다 정한 뒤
64/10000
hr.groo.app
휴가 신청
가족 행사 참석으로 연차를 씁니다. 결재 뒤 인수인계 문서를 공유할게요.
39/1000
메모 · 휴가 사유 — 라이트 · 다크

직접 골라 보기

크기 · 자동 높이 · 최대 높이 · 상태 · 글자 수를 고르면 스펙대로 그린 칸과 그 코드가 바뀐다. 실제로 써서 자라는 모습을 볼 수 있다.

0/1000
크기 size
높이
상태
글자 수
모드
import { Field } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"

<Field label="휴가 사유" maxGraphemeCount={1000}>
  <Textarea placeholder="예: 가족 행사 참석" />
</Field>

Anatomy

팀 점심 — 다음 달 회식비에서 정산하기로 했다. 영수증은 사진으로 올려 둠.
ⓐ Container — 상자ⓑ Value — 글(여백 안)
칸은 상자와 입력으로 이뤄진다
부위설명
ⓐ Container상자 — 테두리 · 바탕 · 모서리. 넘치는 글은 상자 안에서 스크롤한다.
ⓑ Value · Placeholder입력 — 쓴 글, 비었으면 예시 글(placeholder). 위아래 · 좌우 여백은 입력이 가진다.

부위

부위설명
root상자(Container) — 테두리 · 바탕 · 모서리. 넘치는 글은 상자 안에서 잘린다(모서리 밖으로 나가지 않는다)
value입력(<textarea>) — 여백 · 높이를 가진다. 손으로 크기를 바꾸지 않는다(자동 높이가 대신한다)
placeholder빈 칸의 예시 글 — 칸 이름 대신 쓰지 않는다

Properties

Auto Size

자동 높이가 기본이다 — 3줄(large 94 · medium 82)에서 시작해 쓴 만큼 자란다. 최대 높이는 기본으로 없고, 자리마다 정할 수 있다(정하면 그 높이부터 칸 안에서 스크롤). 손잡이(resize)는 두지 않는다.

자동 높이를 끄면(autoSize={false}) 높이를 자리마다 정한다 — 2줄(large 72 · medium 62)보다 낮게 두지 않고, 넘치는 글은 칸 안에서 스크롤한다. 높이는 반드시 정한다(SEED). 켜 둔 채 자란 칸에서 끄면 자랄 때 넣은 높이를 걷어 고정 높이로 돌아가고, 넘치는 글은 스크롤된다.

예: 가족 행사 참석
3줄에서 시작large 94 · medium 82
가족 행사 참석으로 연차를 씁니다. 결재 뒤 인수인계 문서를 공유할게요. 돌아와서 바로 이어서 할게요. 급한 건 메신저로 연락 주세요.
쓴 만큼 자란다최대 높이는 자리마다
가족 행사 참석으로 연차를 씁니다. 결재 뒤 인수인계 문서를 공유할게요. 돌아와서 바로 이어서 할게요.
고정 높이(autoSize false)2줄 72 이상 · 넘치면 스크롤
자동 높이 — 3줄에서 자란다 · 최대 높이에서 멈추고 스크롤 · 고정 높이

높이

조합상태속성값
autoSize=on + size=largeenabled최소 높이94px — 3줄 — 줄 높이 22 × 3 + 위아래 14
autoSize=on + size=largeenabled최대 높이자리마다 — 정하지 않으면 끝없이 자란다. 정하면 그 높이부터 칸 안에서 스크롤
autoSize=on + size=mediumenabled최소 높이82px — 3줄 — 줄 높이 19 × 3 + 위아래 12 는 81, SEED 는 82
autoSize=on + size=mediumenabled최대 높이자리마다 — 정하지 않으면 끝없이 자란다. 정하면 그 높이부터 칸 안에서 스크롤
autoSize=off + size=largeenabled최소 높이72px — 2줄 — 이보다 낮게 두지 않는다(SEED 문서 70). 높이는 자리마다 정하고, 넘치면 칸 안에서 스크롤
autoSize=off + size=mediumenabled최소 높이62px — 2줄 — 줄 높이 19 × 2 + 위아래 12. 높이는 자리마다 정하고, 넘치면 칸 안에서 스크롤

자동 높이

autoSize설명
on (기본)자동 높이 — 3줄에서 시작해 쓴 만큼 자란다(기본)
off고정 높이 — 자리마다 정한 높이(2줄 이상), 넘치면 칸 안에서 스크롤

Size

Input 과 같다 — large(글자 16 · 모서리 12 · 여백 위아래 14 · 좌우 16)는 폰 · 앱, medium(14 · 8 · 12 · 14)은 1280 이상 데스크톱 웹에서만. 웹의 기본은 responsive(1280 미만 large · 이상 medium), 앱은 늘 large 다.

크기

size모서리바뀌는 폭값 글자입력 상하 여백입력 좌우 여백placeholder 글자설명
largeradius-r3 12px—text-t5 16px / 22pxspacing-x3_5 14pxspacing-x4 16pxtext-t5 16px / 22px글자 16 · 모서리 12 — 폰 · 앱
mediumradius-r2 8px—text-t4 14px / 19pxspacing-x3 12pxspacing-x3_5 14pxtext-t4 14px / 19px글자 14 · 모서리 8 — 1280 이상 데스크톱 웹(마우스)에서만
responsive (기본)—1280px — 미만은 large, 이상은 medium 의 값을 쓴다(SEED lg) — 앱은 늘 large————폭에 따라 — 1280 미만 large · 이상 medium. 웹의 기본

State

Input 의 상자형과 같다 — 포커스는 안쪽 2px stroke-neutral-contrast(마우스 · 터치도), 오류는 안쪽 2px stroke-critical-solid(포커스해도 그대로), 비활성 · 읽기 전용은 bg-disabled 바탕(흐리게 하지 않는다), 비활성 글자는 fg-disabled. 읽기 전용은 포커스 표시가 없고(사용자 결정 2026-10-08 — 까닭과 2.4.7 은 Input), 캐럿은 글자색 · 고른 글은 기기 기본 하이라이트다.

예: 가족 행사 참석
기본
가족 행사 참석
포커스
가족 행사 참석
오류
가족 행사 참석
비활성
가족 행사 참석
읽기 전용
라이트
예: 가족 행사 참석
기본
가족 행사 참석
포커스
가족 행사 참석
오류
가족 행사 참석
비활성
가족 행사 참석
읽기 전용
다크
상태 — 기본 · 포커스 · 오류 · 비활성 · 읽기 전용

상태

상태배경테두리테두리 두께커서값 글자색placeholder 색
enabled 기본transparentcolor-stroke-neutral-weak #E5E8EF · 다크 #4047571px — 상자 안쪽에 그린다(inset)textcolor-fg-neutral #1A1F2E · 다크 #F5F6FAcolor-fg-placeholder #767C8B · 다크 #838997
focused 칸에 포커스 — 마우스 · 터치로 눌러도transparentcolor-stroke-neutral-contrast #1A1F2E · 다크 #F5F6FA — 읽기 전용이면 바뀌지 않는다 — 읽기 전용은 포커스 표시가 없다(Input 과 같다, 사용자 결정 2026-10-08)2px — 안쪽에 덧그린다 — 글이 밀리지 않는다textcolor-fg-neutral #1A1F2E · 다크 #F5F6FAcolor-fg-placeholder #767C8B · 다크 #838997
invalid 오류 — Field 의 invalid(aria-invalid). 포커스해도 그대로transparentcolor-stroke-critical-solid #D72323 · 다크 #FF8477 — 포커스해도 그대로2pxtextcolor-fg-neutral #1A1F2E · 다크 #F5F6FAcolor-fg-placeholder #767C8B · 다크 #838997
disabled 비활성 — 값을 바꿀 수 없고 포커스도 받지 않는다color-bg-disabled #F5F6FA · 다크 #353B4D — 흐리게 하지 않는다(v106)color-stroke-neutral-weak #E5E8EF · 다크 #4047571px — 상자 안쪽에 그린다(inset)not-allowedcolor-fg-disabled #8A91A0 · 다크 #838997color-fg-disabled #8A91A0 · 다크 #838997
readonly 읽기 전용 — 포커스 · 복사는 되고 값은 못 바꾼다color-bg-disabled #F5F6FA · 다크 #353B4D — 값은 진한 글자 그대로 — 바탕만으로 편집 칸과 가른다color-stroke-neutral-weak #E5E8EF · 다크 #4047571px — 상자 안쪽에 그린다(inset)textcolor-fg-neutral #1A1F2E · 다크 #F5F6FAcolor-fg-placeholder #767C8B · 다크 #838997

모션

전환시간곡선대상비고
포커스 · 오류 — 테두리motion-duration-d2 100msmotion-ease-easing cubic-bezier(0.35, 0, 0.35, 1)border-color안쪽에 덧그린 2px 의 색이 나타나고 사라진다. 높이가 자랄 때는 움직임을 주지 않는다(글이 바로 보이게)

Guidelines

긴 글은 Textarea 로

한 줄을 넘을 수 있는 글(사유 · 설명 · 메모)은 Textarea 로 받는다 — 한 줄 칸에 200자를 받으면 쓴 글을 한눈에 볼 수 없다. 최대 길이가 있으면 Field 의 글자 수를 붙인다.

자주 쓰지 않게 됐어요. 가계부는 다른 앱으로 옮겼고, 메모만 가끔 썼어요.
42/200
이렇게 — 긴 글은 자라는 칸에 · 최대 길이가 있으면 글자 수
자주 쓰지 않게 됐어요. 가계부는 다른 앱으로 옮겼고
이렇게 하지 않는다 — 한 줄 칸에 200자를 받는다 — 쓴 글을 한눈에 볼 수 없다
긴 글 — 자라는 Textarea 와 글자 수 · 한 줄 칸에 받은 탈퇴 사유

시트 · 대화상자 안에서는 최대 높이

시트나 대화상자처럼 높이가 정해진 곳에서는 최대 높이를 정한다 — 끝없이 자라면 저장 버튼이 화면 밖으로 밀린다.

9:41
메모 추가
가족 행사 참석으로 연차를 씁니다. 결재 뒤 인수인계 문서를 공유할게요. 돌아와서 바로 이어서 할게요. 급한 건 메신저로 연락 주세요. 10월 24일 오후에는 연락이 어려워요. 대신 처리할 사람은 김포레 님입니다.
이렇게 — 시트 안에서는 최대 높이 — 저장 버튼이 제자리에
9:41
메모 추가
가족 행사 참석으로 연차를 씁니다. 결재 뒤 인수인계 문서를 공유할게요. 돌아와서 바로 이어서 할게요. 급한 건 메신저로 연락 주세요. 10월 24일 오후에는 연락이 어려워요. 대신 처리할 사람은 김포레 님입니다. 가족 행사 참석으로 연차를 씁니다. 결재 뒤 인수인계 문서를 공유할게요. 돌아와서 바로 이어서 할게요. 급한 건 메신저로 연락 주세요. 10월 24일 오후에는 연락이 어려워요. 대신 처리할 사람은 김포레 님입니다. 가족 행사 참석으로 연차를 씁니다. 결재 뒤 인수인계 문서를 공유할게요. 돌아와서 바로 이어서 할게요. 급한 건 메신저로 연락 주세요. 10월 24일 오후에는 연락이 어려워요. 대신 처리할 사람은 김포레 님입니다.
이렇게 하지 않는다 — 칸이 끝없이 자라 저장 버튼을 화면 밖으로 밀어낸다
최대 높이 — 시트 안에서 칸이 멈추고 스크롤 · 칸이 자라 저장 버튼을 밀어낸 시트

예시 글은 최소 높이 안에

예시 글(placeholder)은 빈 칸의 최소 높이(3줄) 안에 들게 쓴다 — 칸은 쓴 글로 자라지 예시 글로 자라지 않는다. 앱은 넘는 예시 줄이 소리 없이 잘리고, 웹은 브라우저가 예시 글만큼 칸을 키워(field-sizing) 웹 · 앱이 갈린다. 예시가 길면 줄여 쓰고, 꼭 필요한 안내는 Field 설명으로 옮긴다(2026-10-30 12-2 — 앱 문자 붙여넣기 칸의 예시 5줄이 3줄 높이 밖으로 잘렸다).

코드

레시피 recipes/shadcn/components/ui/textarea.tsx(Textarea)를 Field 안에 둔다. 아래 미리보기는 스펙 값으로 그린 모습이다.

기본

0/1000
import { Field } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"

<Field label="휴가 사유" maxGraphemeCount={1000}>
  <Textarea placeholder="예: 가족 행사 참석" />
</Field>

최대 높이

<Field label="메모">
  <Textarea className="max-h-60" />
</Field>

고정 높이

<Field label="공지 본문">
  <Textarea autoSize={false} className="h-60" />
</Field>

Behavior

인터랙션동작
Click / Tap포커스 — 테두리가 2px 짙어진다.
쓰기 · 붙여넣기자동 높이면 글에 맞춰 바로 자란다(움직임 없이). 최대 높이에 닿으면 멈추고 스크롤이 생긴다.
자동 높이를 끌 때자랄 때 넣은 높이 · 넘침을 걷어 고정 높이(2줄 이상)로 돌아간다 — 넘치는 글은 칸 안에서 스크롤된다.
폭이 바뀔 때줄이 다시 감겨 높이를 다시 맞춘다.
쓰기(최대 글자 수)최대에 닿으면 더 들어가지 않는다 — 한글은 조합이 끝난 뒤 자른다.
Enter줄바꿈. 폼을 제출하지 않는다.
Disabled포커스 · 입력 불가. 커서 not-allowed.
Readonly포커스 · 복사 · 스크롤은 되고 입력은 안 된다. 포커스 표시가 없다(Input 과 같다).

Accessibility

기준검증
WCAG 1.4.3 Color contrast(글자 ≥ 4.5:1)값 fg-neutral 16.41 · 13.42, 읽기 전용 바탕 위 값 15.20 · 10.32 ✓. placeholder fg-placeholder 4.18 · 4.13(시트 다크 3.58) — 4.5:1 밑, 사용자가 대가를 알고 SEED 값을 골랐다(2026-10-16 글자 역할 D7, DESIGN v119). 비활성 fg-disabled 는 기준 밖(비활성 UI)
WCAG 1.4.11 Non-text contrast(≥ 3:1)포커스 테두리 16.41 · 13.42, 오류 5.06 · 6.08 ✓. 기본 1px 테두리(1.23 · 1.56)는 라벨 · placeholder 와 함께 칸을 알린다
WCAG 1.4.10 Reflow자동 높이라 가로 스크롤 없이 글이 감긴다
WCAG 2.4.7 Focus visible편집 칸은 포커스하면 테두리가 2px 짙어진다 ✓. 읽기 전용은 포커스 표시가 없다 ⚠ — 사용자 결정(2026-10-08), 까닭은 Input 의 같은 줄
WCAG 2.5.5 Target Size — Enhanced(AAA ≥ 44×44)최소 높이 62 이상 ✓
ARIA이름은 Field 의 라벨. 오류면 aria-invalid, 설명 · 오류 · 글자 수는 aria-describedby(Field 가 잇는다)

Do / Don't

✅ Do

  • 긴 글은 Textarea 로, 최대 길이가 있으면 글자 수를 붙인다.
  • 시트 · 대화상자 안에서는 최대 높이를 정한다.
  • 자동 높이를 끄면 높이를 정한다(2줄 이상).

❌ Don't

  • 긴 글을 한 줄 칸으로 받기.
  • 손잡이로 높이를 바꾸게 하기.
  • 2줄보다 낮은 고정 높이.
  • 비활성 칸을 흐리게(불투명도) 그리기.

Specification

textarea.yaml 의 규칙을 하나도 빼지 않고 조건마다 그린다 — 웹 · 앱이 Textarea 를 만들 때 이 값을 그대로 쓴다. 조건이 없는 Base 가 모든 조합에 걸리고, 뒤의 규칙이 앞의 같은 값을 덮는다. 상태는 enabled 에서 바뀌는 값만 적었다.

Base

부위상태속성값
rootenabled배경backgroundtransparent
테두리borderColorstroke-neutral-weak#E5E8EF다크 #404757
테두리 두께borderWidth1px상자 안쪽에 그린다(inset)
커서cursortext
전환 대상transitionPropertyborder-color덧그린 2px 의 색만 — 두께는 바로 바뀐다(SEED)
전환 시간transitionDurationmotion-duration-d2100msSEED 는 0.1s 를 바로 적었다
전환 곡선transitionEasingmotion-ease-easingcubic-bezier(0.35, 0, 0.35, 1)
valueenabled값 글자색foregroundfg-neutral#1A1F2E다크 #F5F6FA
굵기fontWeight400
크기 조절resizenone손잡이를 두지 않는다 — 자동 높이가 대신한다
캐럿 색caretColorfg-neutral#1A1F2E다크 #F5F6FA캐럿은 글자색 — 고른 글은 기기 기본 하이라이트(Input 과 같다, 사용자 결정 2026-10-08)
placeholderenabledplaceholder 색foregroundfg-placeholder#767C8B다크 #838997
굵기fontWeight400
rootfocused테두리borderColorstroke-neutral-contrast#1A1F2E다크 #F5F6FA읽기 전용이면 바뀌지 않는다 — 읽기 전용은 포커스 표시가 없다(Input 과 같다, 사용자 결정 2026-10-08)
테두리 두께borderWidth2px안쪽에 덧그린다 — 글이 밀리지 않는다
rootinvalid테두리borderColorstroke-critical-solid#D72323다크 #FF8477포커스해도 그대로
테두리 두께borderWidth2px
rootdisabled배경backgroundbg-disabled#F5F6FA다크 #353B4D흐리게 하지 않는다(v106)
커서cursornot-allowed
valuedisabled값 글자색foregroundfg-disabled#8A91A0다크 #838997
placeholderdisabledplaceholder 색foregroundfg-disabled#8A91A0다크 #838997
rootreadonly배경backgroundbg-disabled#F5F6FA다크 #353B4D값은 진한 글자 그대로 — 바탕만으로 편집 칸과 가른다

size=large

부위상태속성값
rootenabled모서리radiusradius-r312px
valueenabled입력 상하 여백paddingYspacing-x3_514px
입력 좌우 여백paddingXspacing-x416px
값 글자typographytext-t516px / 22px
placeholderenabled글자typographytext-t516px / 22px

size=medium

부위상태속성값
rootenabled모서리radiusradius-r28px
valueenabled입력 상하 여백paddingYspacing-x312px
입력 좌우 여백paddingXspacing-x3_514px
값 글자typographytext-t414px / 19px
placeholderenabled글자typographytext-t414px / 19px

size=responsive

부위상태속성값
rootenabled바뀌는 폭breakpoint1280px미만은 large, 이상은 medium 의 값을 쓴다(SEED lg) — 앱은 늘 large

autoSize=on, size=large

부위상태속성값
valueenabled최소 높이minHeight94px3줄 — 줄 높이 22 × 3 + 위아래 14
최대 높이maxHeight자리마다정하지 않으면 끝없이 자란다. 정하면 그 높이부터 칸 안에서 스크롤

autoSize=on, size=medium

부위상태속성값
valueenabled최소 높이minHeight82px3줄 — 줄 높이 19 × 3 + 위아래 12 는 81, SEED 는 82
최대 높이maxHeight자리마다정하지 않으면 끝없이 자란다. 정하면 그 높이부터 칸 안에서 스크롤

autoSize=off, size=large

부위상태속성값
valueenabled최소 높이minHeight72px2줄 — 이보다 낮게 두지 않는다(SEED 문서 70). 높이는 자리마다 정하고, 넘치면 칸 안에서 스크롤

autoSize=off, size=medium

부위상태속성값
valueenabled최소 높이minHeight62px2줄 — 줄 높이 19 × 2 + 위아래 12. 높이는 자리마다 정하고, 넘치면 칸 안에서 스크롤

SEED 와 다른 점

  • 모양은 상자(outline) 하나 — SEED 디자인 문서의 Textarea 에는 밑줄형이 없다(코드에만 있다).
  • 자동 높이를 끈 2줄 최소 높이를 줄 높이로 계산해 적었다(large 72 · medium 62) — SEED 문서는 70 하나다.

Migration notes

2026-10-30 — 예시 글은 최소 높이 안에

Guidelines 에 "예시 글은 최소 높이 안에" 를 더했다 — 앱 문자 붙여넣기 칸(12-2)의 예시 5줄이 최소 높이 3줄 밖으로 잘렸고, 웹은 예시 글만큼 자라 둘이 갈렸다. 값 변경 없음. 옛 스펙은 textarea.history/v-pre-cleanup-1030.md.

2026-10-08 — 앱 적용이 남긴 것

사용자가 비교 페이지에서 정했다(Input 과 같은 결정).

  • 자동 높이를 끄면 자란 높이를 걷는다 — 레시피가 켜 둔 동안 넣은 인라인 높이 · overflow-y: hidden 을 그대로 두어, 끄고 나서도 큰 칸이 남고 더 쓴 글이 잘린 채 스크롤되지 않았다(desk-front #429). 레시피와 사이트의 칸을 고쳤다.
  • 읽기 전용의 포커스는 표시 없음 · 캐럿은 글자색 · 고른 글은 기기 기본 — Input 의 2026-10-08 과 같다.

2026-10-01 — SEED Textarea 로

Input 과 같은 결정(SEED Text Input)을 따른다 — 투명 바탕 + 1px stroke-neutral-weak, 포커스 · 오류는 안쪽 2px, 비활성 · 읽기 전용은 bg-disabled, 크기 large · medium · 반응형. 높이는 SEED 대로 자동 높이 3줄(94 · 82)에서 시작하고, 끄면 2줄 이상 고정 높이. 옛 스펙은 textarea.history/v-pre-seed-textarea.* 에 남겼다.

옛 Textarea새 Textarea
최소 80 · rows 가 높이를 정함 · 손잡이로 세로 크기 조절자동 높이 3줄(94 · 82)에서 자란다, 최대 높이는 자리마다 · 손잡이 없음
회색 채운 바탕 · 모서리 4 · 여백 8 / 12투명 바탕 · 모서리 12 · 8 · 여백 14 / 16 · 12 / 14
글자 body-md 15 / 1.6large t5 16 / 22 · medium t4 14 / 19
포커스 브랜드 링 · 오류 빨간 링 · 비활성 흐림 50%Input 과 같다(안쪽 2px · bg-disabled)

레시피는 <textarea> 하나에서 상자(div) + 입력으로 바뀌었다 — className 은 입력에(최대 · 고정 높이 max-h-* · h-* 도 여기), 상자에는 rootClassName.

제품은 앱 적용 단계에서 옮긴다(2026-10-01 조사).

  • Desk 웹 — Textarea 9곳, 자동 높이 · 최대 높이 · 글자 수 0곳. 거래 메모 3곳은 인라인으로 66(최소 80보다 작다). 긴 글을 한 줄 칸으로 받는 곳 3.
  • Desk 앱 — 여러 줄 8곳 — 고정 2줄 67 · 3줄 93 · 6줄 170 · 자동 8 → 12줄 · 5 → 8줄로 제각각, 같은 "설명" 이 화면마다 2줄 · 1줄. 탈퇴 사유(200자) · 메모류를 한 줄 칸으로 받는다.
  • HR 웹 — Textarea 12곳, 최소 64(2곳만 80), field-sizing-content 라 rows 가 무시된다, 최대 높이 0곳, 손잡이 제각각. 공지 수정 대화상자는 본문을 빈칸으로 연다.

이 페이지