Link#
내부 라우팅 또는 외부 URL로 이동하는 링크 텍스트 컴포넌트입니다. 항상 표시되는 밑줄 장식과 외부 링크 표시를 지원합니다.
Live Preview#
class LinkDefaultExample extends StatelessComponent {
const LinkDefaultExample({super.key});
@override
Component build(BuildContext context) {
return Link(
href: '#',
child: const Text('Click here'),
);
}
}
class LinkDefaultExample extends StatelessWidget {
const LinkDefaultExample({super.key});
@override
Widget build(BuildContext context) {
return const Link(
href: '#',
child: Text('Click here'),
);
}
}
class LinkExternalExample extends StatelessComponent {
const LinkExternalExample({super.key});
@override
Component build(BuildContext context) {
return Link(
href: 'https://example.com',
external: true,
child: const Text('External Link'),
);
}
}
class LinkExternalExample extends StatelessWidget {
const LinkExternalExample({super.key});
@override
Widget build(BuildContext context) {
return const Link(
href: 'https://example.com',
external: true,
child: Text('External Link'),
);
}
}
class LinkNoUnderlineExample extends StatelessComponent {
const LinkNoUnderlineExample({super.key});
@override
Component build(BuildContext context) {
return Link(
href: '#',
underline: false,
child: const Text('No Underline'),
);
}
}
class LinkNoUnderlineExample extends StatelessWidget {
const LinkNoUnderlineExample({super.key});
@override
Widget build(BuildContext context) {
return const Link(
href: '#',
underline: false,
child: Text('No Underline'),
);
}
}
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,
),
);
}
}
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,
),
);
}
}
사용 시기 (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 필드#
| 필드 | 타입 | 설명 |
|---|---|---|
color | CoreColor? | 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)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | Link | Link |
| 렌더 요소 | GestureDetector + Text |
<div role="link"> |
| 외부 링크 | onPressed 핸들러가 외부 의도 처리 | target="_blank" |
관련 컴포넌트 (Related Components)#
- Button: 탐색이 아닌 액션 실행에 사용
- Text: 링크가 없는 일반 텍스트에 사용
- Breadcrumb: 계층적 페이지 탐색 경로 표시에 사용