Link | CoUI
LogoCoUI

Link

내부 또는 외부 URL로 이동하는 링크 텍스트 컴포넌트

Link#

내부 라우팅 또는 외부 URL로 이동하는 링크 텍스트 컴포넌트입니다. 항상 표시되는 밑줄 장식과 외부 링크 표시를 지원합니다.

Live Preview#

사용 시기 (When to Use)#

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

  • 본문 텍스트 중간에 인라인 링크가 필요할 때
  • 외부 사이트로 이동하는 링크를 명시적으로 표시할 때
  • 이용약관, 개인정보처리방침 같은 보조 링크가 필요할 때

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

  • Button: 사용자 액션을 유발하는 클릭 가능한 요소에 (탐색이 아닌 경우)
  • Breadcrumb: 계층적 페이지 탐색 경로를 표시할 때

기본 사용법 (Basic Usage)#

// 기본 링크 (밑줄 표시)
Link(
  href: '#',
  child: Text('Click here'),
)

// 외부 URL 링크 (새 탭)
Link(
  href: 'https://example.com',
  external: true,
  child: Text('External Link'),
)

// 밑줄 없는 링크
Link(
  href: '#',
  underline: false,
  child: Text('No Underline'),
)

// 탭 콜백 사용
Link(
  href: 'https://coui.cocode.im',
  onPressed: handleOpenDocs,
  child: Text('CoUI 문서'),
)
// 기본 링크 (밑줄 표시)
Link(
  href: '#',
  child: const Text('Click here'),
)

// 외부 URL 링크 (새 탭)
Link(
  href: 'https://example.com',
  external: true,
  child: const Text('External Link'),
)

// 밑줄 없는 링크
Link(
  href: '#',
  underline: false,
  child: const Text('No Underline'),
)

// 클릭 콜백 사용
Link(
  href: 'https://coui.cocode.im',
  onPressed: handleOpenDocs,
  child: const Text('CoUI 문서'),
)

Props / Parameters#

속성타입기본값설명
href String 필수 이동할 URL. child가 없으면 이 문자열이 링크 텍스트로 렌더링됨
onPressed VoidCallback? (Flutter) / CoreVoidCallback? (Web) null 활성화(탭/클릭/키보드 Enter) 시 호출되는 콜백
external bool false 외부 링크 여부. Web에서 target="_blank" + rel="noopener noreferrer" 의도 적용
underline bool true 밑줄 장식 표시 여부. 항상 표시(호버 전용 아님)
child Widget? (Flutter) / Component? (Web) null 링크 내용. null이면 href가 일반 텍스트로 렌더링됨
linkStyle CoreLinkStyle? null 색상 / 밑줄 색상 / 밑줄 오프셋 / 전환 duration / 라벨 텍스트 스타일 오버라이드

빠른 오버라이드 (Chain)#

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

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

  @override
  Widget build(BuildContext context) {
    return const Link(
      href: '#',
      child: Text('Click here'),
    ).withStyle(
      const CoreLinkStyle(
        color: CoreColor.token(CoreColors.secondary),
        underlineColor: CoreColor.token(CoreColors.tertiary),
        underlineOffset: CoreSpace.space6,
      ),
    );
  }
}
class LinkChainExample extends StatelessComponent {
  const LinkChainExample({super.key});

  @override
  Component build(BuildContext context) {
    return Link(
      href: '#',
      child: const Text('Click here'),
    ).withStyle(
      const CoreLinkStyle(
        color: CoreColor.token(CoreColors.secondary),
        underlineColor: CoreColor.token(CoreColors.tertiary),
        underlineOffset: CoreSpace.space6,
      ),
    );
  }
}

변형 (Variants)#

Default#

기본 primary 색상과 밑줄을 사용합니다. 본문 내 링크에 적합합니다.

Link(
  href: '#',
  child: Text('Click here'),
)

External#

external: true로 새 탭에서 열리는 외부 링크를 표시합니다.

Link(
  href: 'https://example.com',
  external: true,
  child: Text('External Link'),
)

No Underline#

underline: false로 밑줄 없는 링크를 표시합니다. 부가 정보 링크에 적합합니다.

Link(
  href: '#',
  underline: false,
  child: Text('No Underline'),
)

스타일 커스터마이징 (Styling)#

모든 시각 chrome은 linkStyle 단일 슬롯(CoreLinkStyle)으로 전달합니다.

Link(
  href: '#',
  linkStyle: const CoreLinkStyle(
    color: CoreColor.token(CoreColors.secondary),
    underlineColor: CoreColor.token(CoreColors.secondary),
  ),
  child: Text('Secondary Link'),
)

CoreLinkStyle 필드#

필드타입설명
colorCoreColor?Link text colour override.
underlineColor CoreColor? Underline stroke colour override.
underlineOffset double? Underline offset override (logical px).
transitionDuration Duration? Colour-transition duration override for hover / focus feedback.
labelStyle CoreTextStyle? Link label text style override (applied to the link's text child).
clickableStyle CoreClickableStyle? Nested [CoreClickableStyle] slot for the composed Clickable (press scale / durations / focus ring / disabled opacity). Merged on top of [defaultClickableStyle] and raw-forwarded — the Clickable's own resolver fills the remaining defaults.

동작 스펙 (Behavior)#

인터랙션#

  • 클릭/탭: onPressed 호출
  • 호버: 커서가 포인터로 변경
  • 외부 링크: external: true 시 Web에서 새 탭으로 열림

애니메이션#

  • 색상 전환: 150ms ease-in-out (CoreLinkStyle.transitionDuration)

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

✅ Do#

외부 URL 에는 external: true 명시

Link(
  href: 'https://example.com',
  external: true,
  child: Text('External Link'),
)

이유: external: true 는 Web 에서 target="_blank" + rel="noopener noreferrer" 를 실제로 적용하고, Flutter 에서도 onPressed 핸들러가 외부 이동 의도를 판단할 수 있는 신호가 됩니다. 생략하면 두 플랫폼 모두 새 탭/보안 처리를 임의로 판단해야 합니다.


❌ Don't#

탐색이 아닌 액션 트리거에 사용 금지

// ❌ 페이지 이동이 아니라 폼 제출 액션인데 Link 사용
Link(href: '#', onPressed: submitForm, child: Text('제출'))

이유: Link 는 Web role="link" / Flutter Semantics(link: true) 로 노출되어 스크린 리더가 "다른 곳으로 이동한다"고 안내합니다. 실제로는 폼을 제출하는 액션이라면 시맨틱과 실제 동작이 어긋나므로 Button 을 사용해야 합니다.

접근성 (Accessibility)#

키보드 인터랙션#

동작
Tab링크로 포커스 이동
Enter링크 활성화

스크린 리더#

  • Flutter: Semantics(link: true, button: true) 자동 적용
  • Web: role="link" + tabindex="0" 부여; external이면 data-external 속성 추가

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

항목FlutterWeb
클래스명LinkLink
렌더 요소 GestureDetector + Text <div role="link">
외부 링크onPressed 핸들러가 외부 의도 처리target="_blank"
  • Button: 탐색이 아닌 액션 실행에 사용
  • Text: 링크가 없는 일반 텍스트에 사용
  • Breadcrumb: 계층적 페이지 탐색 경로 표시에 사용