Icon | CoUI
LogoCoUI

Icon

CoUI 디자인 시스템의 아이콘 컴포넌트

Icon#

CoUI 디자인 시스템의 통일된 아이콘 컴포넌트입니다. Iconify 생태계(Lucide, Radix, Bootstrap, HeroIcons) 아이콘을 IconName 참조로 렌더합니다. Flutter와 Web이 동일한 API동일한 아이콘 레퍼런스를 사용합니다.

앱은 네 카탈로그를 자유롭게 쓸 수 있지만, CoUI 자신의 컴포넌트는 LucideIcons 하나만 씁니다. 각 세트는 자기 그리드와 자기 획 두께로 그려져, 같은 size 를 요청해도 시각적 무게가 다르게 도착하기 때문입니다 — 한 벌에서 온 체크와 다른 벌에서 온 chevron 이 나란히 있으면 선택이 아니라 렌더 버그로 읽힙니다. 한 앱 안에서 섞을 때도 같은 이유로 인접한 컨트롤끼리는 한 세트로 맞추는 편이 좋습니다.

Live Preview#

사용 시기 (When to Use)#

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

  • 버튼, 메뉴, 네비게이션 항목에 시각적 힌트가 필요할 때
  • 텍스트 없이 아이콘만으로 의미를 전달해야 할 때 (접근성 레이블 필수)
  • CoUI 디자인 시스템의 통일된 아이콘 세트를 사용할 때

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

  • Badge: 아이콘 위에 숫자나 상태 표시가 필요할 때 IconBadge를 조합
  • Fab: 아이콘 버튼을 강조된 액션 버튼으로 표시할 때

기본 사용법 (Basic Usage)#

Icon의 모든 시각 커스터마이징은 iconStyle: CoreIconStyle(...)로 단일화되어 있습니다.

// 기본 아이콘 (디자인 시스템 default — 24px / onSurface)
const Icon(LucideIcons.house);

// 크기 지정
const Icon(
  LucideIcons.house,
  iconStyle: CoreIconStyle(size: 28),
);

// 다른 아이콘 세트
const Icon(RadixIcons.chevronLeft, iconStyle: CoreIconStyle(size: 16));
const Icon(BootstrapIcons.gear, iconStyle: CoreIconStyle(size: 20));

// HeroIcons 스타일 선택
const Icon(HeroIcons.arrowLeft.outline, iconStyle: CoreIconStyle(size: 24));
const Icon(HeroIcons.arrowLeft.solid, iconStyle: CoreIconStyle(size: 24));

// 크기 + 색상
Icon(
  LucideIcons.heart,
  iconStyle: CoreIconStyle(
    size: 28,
    color: Theme.of(context).colorScheme.tertiary,
  ),
);

// 같은 스타일을 여러 인스턴스에 재사용
final dangerIcon = CoreIconStyle(
  size: 20,
  color: Theme.of(context).colorScheme.error,
);

Icon(LucideIcons.alertTriangle, iconStyle: dangerIcon);
Icon(LucideIcons.x, iconStyle: dangerIcon);
// 기본 아이콘
const Icon(LucideIcons.house);

// 크기 지정
const Icon(
  LucideIcons.house,
  iconStyle: CoreIconStyle(size: 28),
);

// 다른 아이콘 세트
const Icon(RadixIcons.chevronLeft, iconStyle: CoreIconStyle(size: 16));
const Icon(BootstrapIcons.gear, iconStyle: CoreIconStyle(size: 20));

// HeroIcons 스타일 선택
const Icon(HeroIcons.arrowLeft.outline, iconStyle: CoreIconStyle(size: 24));
const Icon(HeroIcons.arrowLeft.solid, iconStyle: CoreIconStyle(size: 24));

// 크기 + 색상 — Web 의 color 는 Tailwind colour token 문자열
Icon(
  LucideIcons.heart,
  iconStyle: CoreIconStyle(
    size: 28,
    color: context.colorScheme.tertiary, // 'tertiary' 토큰
  ),
);

빠른 오버라이드 (Chain)#

이미 만든 Icon 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle 체인을 쓸 수 있습니다. 생성자의 iconStyle 인자와 동일하게 동작하지만, 이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.

class IconChainExample extends StatelessWidget {
  const IconChainExample({super.key});

  @override
  Widget build(BuildContext context) {
    return const Icon(
      LucideIcons.house,
      iconStyle: CoreIconStyle(size: 28),
    ).withStyle(
      const CoreIconStyle(
        size: CoreIconSize.size32,
        color: CoreColor.token(CoreColors.primary),
      ),
    );
  }
}
class IconChainExample extends StatelessComponent {
  const IconChainExample({super.key});

  @override
  Component build(BuildContext context) {
    return const Icon(
      LucideIcons.house,
      iconStyle: CoreIconStyle(size: 28),
    ).withStyle(
      const CoreIconStyle(
        size: CoreIconSize.size32,
        color: CoreColor.token(CoreColors.primary),
      ),
    );
  }
}

Props / Parameters#

속성타입 (Flutter)타입 (Web)기본값설명
icon IconName IconName 필수 (positional) 표시할 아이콘 (LucideIcons.* 등)
iconStyle CoreIconStyle? CoreIconStyle? null 아이콘 크기/색상 (Style 시스템 참조)

스타일 시스템 (Style System)#

Icon 의 모든 시각 오버라이드는 단일 iconStyle (CoreIconStyle) 으로 흐릅니다. IconName 식별자만 위젯 파라미터로 직접 전달합니다.

CoreIconStyle 필드#

필드타입설명
size double? Icon size in logical pixels (Flutter) / CSS pixels (Web). null → inherit.
color CoreColor? Icon colour. null → inherit.

Resolve chain#

design system default
  → CoreIconTheme.style                        // 프로젝트 공통
  → parent component slot override             // 예: CoreButtonStyle.leadingIconStyle
  → widget.iconStyle                           // 인스턴스별

각 레이어는 CoreIconStyle 의 어떤 필드든 부분적으로 채울 수 있습니다. null 인 필드는 다음 레이어로 넘겨주고, non-null 인 필드는 해당 레이어에서 확정됩니다.

색상 처리 차이점#

  • Flutter: Color 객체로 받아 ColorFilter.mode(color, BlendMode.srcIn)으로 tint
  • Web: Tailwind colour token 문자열('tertiary' 등)로 받아 text-${token} class 적용
  • 양쪽 모두 currentColor 기반 SVG를 tint하는 결과는 동일

테마 연동#

프로젝트 레벨 기본값은 CoreComponentTheme.iconCoreIconTheme.style로 지정합니다.

CoUIApp(
  theme: ThemeData.fromCore(
    CoreThemePresets.light,
    coreComponentTheme: const CoreComponentTheme(
      icon: CoreIconTheme(
        style: CoreIconStyle(
          size: 20,
          color: CoreColor.token(CoreColors.onSurfaceVariant),
        ),
      ),
    ),
  ),
  home: MyHomePage(),
)

이후 iconStyle이 null이거나 size/color가 null인 모든 Icon은 위 default를 따릅니다.

크기 권장값#

용도크기
인라인 텍스트16.0
버튼 내 아이콘20.0
기본 아이콘24.0
강조 아이콘32.0
히어로 아이콘48.0

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

✅ Do#

색상을 생략해 부모 색을 자동으로 상속

Icon(LucideIcons.check)

iconStyle.color를 생략하면 Web은 currentColor로 부모 색을 상속하고 Flutter는 ambient IconTheme을 따릅니다 — 배경색이 다른 버튼/배지 안에 넣어도 매번 색을 새로 지정할 필요 없이 자동으로 어울리는 색이 됩니다.


❌ Don't#

한 화면 안에서 아이콘 세트를 섞어 쓰지 않기

// ❌ 인접한 아이콘에 서로 다른 세트 사용
Row(
  children: [
    Icon(LucideIcons.chevronRight),
    Icon(RadixIcons.chevronRight),
  ],
)

각 세트는 자기 그리드와 획 두께로 그려져 같은 size를 줘도 시각적 무게가 다르게 도착합니다 — 인접한 컨트롤끼리 세트가 섞이면 선택이 아니라 렌더 버그로 보입니다. CoUI 컴포넌트 내부는 물론, 앱 코드에서도 인접한 아이콘끼리는 LucideIcons 한 세트로 통일하세요.

접근성 (Accessibility)#

  • 아이콘은 시각적 요소이므로, 텍스트 레이블이 없는 독립 아이콘에는 tooltip 또는 부모 aria-label을 제공하세요
  • Flutter: Semantics wrapper 사용
  • Web: <iconify-icon>은 기본적으로 aria-hidden 상태 — 의미 전달이 필요하면 부모 요소에 aria-label 지정
  • Button: 아이콘을 액션 버튼 내에 포함할 때 — CoreButtonStyle.leadingIconStyle / trailingIconStyle로 nested
  • Badge: 아이콘 위에 알림 카운트 표시
  • Fab: 아이콘을 주요 액션 FAB로 표시