Avatar | CoUI

Avatar

사용자 아바타 컴포넌트

Avatar#

사용자 프로필 이미지 또는 이니셜을 표시하는 아바타 컴포넌트입니다.

Live Preview#

Web
Flutter
Loading Flutter...
class AvatarDefaultExample extends StatefulComponent {
  const AvatarDefaultExample({super.key});

  @override
  State<AvatarDefaultExample> createState() => _AvatarDefaultExampleState();
}

class _AvatarDefaultExampleState extends State<AvatarDefaultExample> {
  @override
  Component build(BuildContext context) {
    return CoAvatar(
      initials: 'AB',
    );
  }
}
class AvatarDefaultExample extends StatefulWidget {
  const AvatarDefaultExample({super.key});

  @override
  State<AvatarDefaultExample> createState() => _AvatarDefaultExampleState();
}

class _AvatarDefaultExampleState extends State<AvatarDefaultExample> {
  @override
  Widget build(BuildContext context) {
    return const CoAvatar(
      initials: 'AB',
    );
  }
}

사용 시기 (When to Use)#

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

  • 사용자 프로필 이미지 또는 이니셜을 표시할 때
  • 댓글, 채팅, 팀 멤버 목록에서 사용자를 시각적으로 식별할 때
  • 온라인/오프라인 상태를 함께 표시해야 할 때

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

  • Icon: 사용자가 아닌 일반 아이콘을 표시할 때
  • Badge: 텍스트 레이블이 필요한 상태 표시일 때
  • Image: 프로필이 아닌 일반 이미지를 표시할 때

기본 사용법 (Basic Usage)#

// 이미지 아바타
CoAvatar(
  imageUrl: 'https://example.com/photo.jpg',
  size: CoreComponentSize.md,
)

// 이니셜 아바타
CoAvatar(
  initials: '홍',
  size: CoreComponentSize.lg,
)

// 링 효과
CoAvatar(
  imageUrl: user.photoUrl,
  ring: true,
)

// 커스텀 child
CoAvatar(
  size: CoreComponentSize.sm,
  child: Icon(Icons.person),
)
// 이미지 아바타
CoAvatar(
  imageUrl: 'https://example.com/photo.jpg',
  size: CoreComponentSize.md,
)

// 이니셜 아바타
CoAvatar(
  initials: '홍',
  size: CoreComponentSize.lg,
)

// 링 효과
CoAvatar(
  imageUrl: 'https://example.com/photo.jpg',
  size: CoreComponentSize.md,
  ring: true,
)

// 커스텀 child
CoAvatar(
  size: CoreComponentSize.sm,
  child: text('JD'),
)

Props / Parameters#

속성타입기본값설명
imageUrl String? null 프로필 이미지 URL
initials String? null 이니셜 텍스트
size CoreComponentSize md 아바타 크기
ringboolfalse링 보더 표시 여부
backgroundColor Color? / CoreColor? null 배경색 (legacy — avatarStyle.backgroundColor 권장)
child Widget? null 커스텀 내용 (imageUrl/initials 대체)
badge Widget? / Component? null 아바타 위에 오버레이 되는 배지
badgeAlignment AlignmentGeometry? / Object? null 배지 정렬
badgeGap double? null 배지와 아바타 사이 갭
avatarStyle CoreAvatarStyle<Color>? / CoreAvatarStyle<CoreColor>? null 인스턴스 스타일 (Style 시스템 참조)

스타일 시스템 (Style System)#

Avatar 의 모든 chrome / dimensional / nested-slot 오버라이드는 CoreAvatarStyle<Clr> 단일 슬롯으로 흐릅니다 (Epic #1302 원칙 6/7/8). 시맨틱 enum (size) 과 behaviour (ring / badge / imageUrl / initials) 는 위젯 파라미터로 직접 전달합니다.

시맨틱 vs 스타일#

  • 시맨틱 enum / behaviour: 위젯 파라미터로 직접 (size, ring, imageUrl, initials, child, badge, badgeAlignment, badgeGap)
  • chrome / dimensional / 슬롯 스타일: CoreAvatarStyle 한 곳으로 (backgroundColor / foregroundColor / borderRadius / ringColor / ringWidth / fallbackTextStyle)

Resolve chain#

design system default for avatar
  → CoreAvatarTheme.style                  // 프로젝트 공통
  → parent component slot override
  → widget.avatarStyle                     // 인스턴스별

fallbackTextStyle 슬롯은 자기 컴포넌트의 자체 resolve chain 으로 다시 한 번 머지됩니다.

슬롯 매핑 (CoreAvatarStyle 6 필드)#

필드타입 (Flutter)적용 영역
backgroundColor Color? 아바타 배경 (legacy backgroundColor prop 보다 우선 적용)
foregroundColorColor?이니셜 폴백 텍스트 색
borderRadius double? 모서리 반지름 (px). null → 원형 (shape: circle)
ringColorColor?ring: true 일 때 링 색
ringWidth double? ring: true 일 때 링 두께 (px)
fallbackTextStyle CoreTextStyle<Color>? 이니셜 폴백 텍스트 스타일 (이미지 / 자식 없을 때 표시)

Migration — 옛 평면 chrome → 새 위치 매핑#

옛 위치 (legacy)새 위치
backgroundColor 위젯 prop avatarStyle.backgroundColor (인스턴스) 또는 CoreAvatarTheme.style.backgroundColor (프로젝트)
인스턴스 ring 색상 (불가능)avatarStyle.ringColor
인스턴스 ring 두께 (불가능)avatarStyle.ringWidth
인스턴스 모서리 반지름 (불가능 — 항상 circle)avatarStyle.borderRadius
인스턴스 이니셜 폴백 텍스트 스타일 (불가능)avatarStyle.fallbackTextStyle

backgroundColor prop 은 호환을 위해 유지되지만 새 코드에서는 avatarStyle.backgroundColor 사용을 권장합니다.

사용 예 (Flutter)#

CoAvatar(
  initials: 'JD',
  ring: true,
  avatarStyle: CoreAvatarStyle(
    backgroundColor: Color(0xFF3B82F6),
    foregroundColor: Colors.white,
    ringColor: Color(0xFFE11D48),
    ringWidth: 3,
    fallbackTextStyle: CoreTextStyle(fontWeight: 700),
  ),
)

사용 예 (Web)#

CoAvatar(
  initials: 'JD',
  ring: true,
  avatarStyle: CoreAvatarStyle<CoreColor>(
    backgroundColor: CoreColor.fromHex('#3B82F6'),
    fallbackTextStyle: CoreTextStyle<CoreColor>(fontWeight: 700),
  ),
)

변형 (Variants)#

크기#

크기픽셀
XSCoreComponentSize.xs24px
SMCoreComponentSize.sm32px
MDCoreComponentSize.md40px
LGCoreComponentSize.lg48px
XLCoreComponentSize.xl64px

링 효과#

CoAvatar(imageUrl: url, ring: true)
CoAvatar(imageUrl: url, ring: false)

배경색 커스텀#

CoAvatar(initials: 'AB', backgroundColor: Colors.blue)
CoAvatar(initials: 'CD', backgroundColor: Colors.green)

동작 스펙 (Behavior)#

이미지 로딩#

  • ImageProvider(Flutter) 또는 <img> 태그(Web)로 이미지 표시
  • 이미지 로드 실패 시 자동으로 initials 텍스트로 폴백
  • Flutter: Avatar.network() 생성자에서 cacheWidth/cacheHeight로 메모리 최적화
  • Web: <img> 태그에 alt 속성 자동 적용

Ring 효과#

  • Flutter: 2px gap + 1px stroke, ring: true로 활성화
  • Web: CSS ring-2 ring-primary ring-offset-2 클래스, ring: true로 활성화
CoAvatar(
  imageUrl: 'https://example.com/photo.jpg',
  ring: true,
)

이미지 폴백#

  • imageUrlinitials를 함께 제공하면 이미지 로드 실패 시 이니셜로 폴백
  • child가 있으면 imageUrl/initials보다 우선
CoAvatar(
  imageUrl: 'https://example.com/photo.jpg',
  initials: 'JD',
  size: CoreComponentSize.md,
)

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

✅ Do#

이미지와 이니셜 폴백을 항상 함께 제공하세요.

CoAvatar(
  imageUrl: user.photoUrl,
  initials: 'JD',
)

이미지 로드 실패 시 이니셜이 표시되어 사용자를 식별할 수 있습니다.


❌ Don't#

이미지 없이 빈 아바타를 표시하지 마세요.

이니셜이나 기본 아이콘 없는 빈 원형은 사용자를 식별할 수 없습니다.

✅ Do#

그룹에서 maxCount를 설정하세요.

Row(
  children: teamMembers.take(5).map((m) => CoAvatar(
    imageUrl: m.photo,
    size: CoreComponentSize.sm,
  )).toList(),
)

많은 아바타가 나열되면 레이아웃이 깨집니다. 3~5개가 적절합니다.


❌ Don't#

아바타 크기를 컨텍스트에 맞지 않게 사용하지 마세요.

댓글 목록에 XL(72px) 아바타를 사용하면 콘텐츠보다 아바타가 강조됩니다. 인라인에는 SM(32px), 프로필 헤더에는 LG(56px) 이상을 사용하세요.

✅ Do#

상태 표시는 실시간 정보에만 사용하세요.

CoAvatar(
  imageUrl: user.photoUrl,
  ring: user.isOnline,
)

온라인/오프라인 같은 실시간 상태만 뱃지로 표시합니다.


❌ Don't#

정적 역할 정보를 아바타 뱃지로 표시하지 마세요.

"관리자", "멤버" 같은 역할은 별도 텍스트 레이블로 표시하세요.

접근성 (Accessibility)#

스크린 리더#

  • Flutter: 이미지 아바타에 사용자 이름 시맨틱 제공. 이니셜 텍스트가 읽힘
  • Web: <img> 태그의 alt 속성으로 사용자 이름 전달. 폴백은 텍스트가 직접 읽힘

최소 크기#

  • 인터랙티브 아바타(클릭 가능): 최소 44×44dp 터치 영역 확보
  • XS(24px) 아바타는 표시 전용으로만 사용

색상 대비#

  • 이니셜 텍스트와 배경색의 대비 WCAG AA 준수
  • Ring 효과는 색상 이외의 시각적 구분(간격)도 제공

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

항목FlutterWeb
크기 시스템연속적 double (기본 40px)AvatarSize enum (xs~xl)
이미지 ImageProvider 추상화 <img> 태그 src
폴백자동 이니셜 표시fallback prop
뱃지AvatarBadge 위젯 (색상, 크기, 커스텀)미지원
Ring ring: Color (2px gap + 1px stroke) ring: bool (CSS ring 클래스)
그룹 오버랩CustomClipper 8방향CSS -space-x-4 2방향
그룹 maxCount미지원 (수동 구현)max: int + "+N" 뱃지
테마 AvatarTheme (size, borderRadius, textStyle) Tailwind CSS 클래스
이니셜 추출Avatar.getInitials()Avatar.getInitials()
  • Badge: 상태 텍스트 레이블. Avatar의 badge 대신 텍스트 기반 상태 표시
  • Icon: 아이콘 시스템. Avatar의 커스텀 child로 아이콘 배치 가능
  • HoverCard: 호버 미리보기. Avatar에 호버하면 프로필 카드 표시

조합 예제#

// 댓글 목록 패턴
ListView.builder(
  itemBuilder: (context, index) {
    final comment = comments[index];
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        HoverCard(
          hoverBuilder: (context) => UserProfileCard(user: comment.author),
          child: Avatar(
            imageUrl: comment.author.photoUrl,
            initials: Avatar.getInitials(comment.author.name),
            size: AvatarSize.sm,
            status: comment.author.isOnline
              ? AvatarStatus.online
              : null,
          ),
        ),
        SizedBox(width: 12),
        Expanded(child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(comment.author.name,
              style: TextStyle(fontWeight: FontWeight.bold)),
            Text(comment.body),
          ],
        )),
      ],
    );
  },
)