Tag Group 텍스트 태그를 수평으로 나열해 여러 속성·상태·메타데이터를 한눈에 보여주는 정보 요약 컴포넌트입니다.
@seed-design/lynx-react@0.1.0, @seed-design/lynx-css@0.1.0
import "./styles" ;
import { root } from "@lynx-js/react" ;
import { TagGroup, useSeedClassName } from "@seed-design/lynx-react" ;
function Root () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< page className = {seedClassName}>
< view className = "tag-group-preview" >
< TagGroup.Root className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >500m</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >3분 전</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
</ view >
</ page >
);
}
root. render (< Root />);
npx @seed-design/cli add ui:tag-group pnpm dlx @seed-design/cli add ui:tag-group yarn dlx @seed-design/cli add ui:tag-group bun x @seed-design/cli add ui:tag-group
의존성 설치
npm install @seed-design/lynx-react yarn add @seed-design/lynx-react pnpm add @seed-design/lynx-react bun add @seed-design/lynx-react 아래 코드를 복사 후 붙여넣고 사용하세요 /**
* @file ui:tag-group
* @requires @seed-design/lynx-react@>=0.1.0 <1.0.0
* @requires @seed-design/lynx-css@>=0.1.0 <1.0.0
**/
/**
* @see https://seed-design.io/lynx/components/tag-group
*/
import * as React from "@lynx-js/react" ;
import { TagGroup as SeedTagGroup } from "@seed-design/lynx-react" ;
export interface TagGroupRootProps extends SeedTagGroup . RootProps {}
export const TagGroupRoot = SeedTagGroup.Root;
export interface TagGroupItemProps extends Omit < SeedTagGroup . ItemProps , "children" > {
label : React . ReactNode ;
}
export const TagGroupItem = React. forwardRef < unknown , TagGroupItemProps >(
({ label , ... props }, ref ) => {
return (
< SeedTagGroup.Item { ... props} ref = {ref}>
< SeedTagGroup.ItemLabel >{label}</ SeedTagGroup.ItemLabel >
</ SeedTagGroup.Item >
);
},
);
TagGroupItem.displayName = "TagGroupItem" ;
/**
* This file is a snippet from SEED Design, helping you get started quickly with @seed-design/* packages.
* You can extend this snippet however you want.
*/
설치한 snippet은 TagGroupRoot와 TagGroupItem을 export 합니다. TagGroupItem은 label prop을 받아 내부에서 Lynx <text> label을 렌더합니다.
import { TagGroupRoot, TagGroupItem } from "@/components/ui/tag-group" ;
export function App () {
return (
< TagGroupRoot size = "t2" >
< TagGroupItem label = "동네 인증" />
< TagGroupItem label = "매너 온도 42.0°C" />
< TagGroupItem tone = "brand" weight = "bold" label = "추천" />
</ TagGroupRoot >
);
}
TagGroupRoot의 size·weight·tone은 Context로 하위 TagGroupItem에 전파되며, 개별 TagGroupItem에서 prop으로 덮어쓸 수 있습니다. 구분자는 기본 "·"이고 separator prop으로 바꿀 수 있습니다.
TagGroupItem은 flexShrink를 지원합니다. 긴 태그가 있는 레이아웃에서 item의 축소 우선순위를 조정해야 할 때 사용하세요.
TagGroup은 정보를 읽기 전용으로 나열하는 컴포넌트입니다. 단일·다중 선택, 선택 값 변경, 비활성화 상태를 위한 API는 제공하지 않습니다. 사용자가 값을 선택해야 한다면 단일 선택에는 RadioGroup, 다중 선택에는 Checkbox를 사용하세요.
style?CSSProperties | undefined
children?React.ReactNode
className?string | undefined
labelReact.ReactNode
flexShrink?boolean | Property.FlexShrink | undefined
className?string | undefined
style?CSSProperties | undefined
import "./styles" ;
import { root } from "@lynx-js/react" ;
import { TagGroup, VStack, useSeedClassName } from "@seed-design/lynx-react" ;
function Root () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< page className = {seedClassName}>
< VStack className = "tag-group-preview" gap = "spacingY.componentDefault" >
< TagGroup.Root size = "t2" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >거리 500m</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >3분 전</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
< TagGroup.Root size = "t3" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >거리 500m</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >3분 전</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
< TagGroup.Root size = "t4" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >거리 500m</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >3분 전</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
</ VStack >
</ page >
);
}
root. render (< Root />);
import "./styles" ;
import { root } from "@lynx-js/react" ;
import { TagGroup, VStack, useSeedClassName } from "@seed-design/lynx-react" ;
function Root () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< page className = {seedClassName}>
< VStack className = "tag-group-preview" gap = "spacingY.componentDefault" >
< TagGroup.Root weight = "regular" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >regular</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
< TagGroup.Root weight = "bold" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >bold</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
</ VStack >
</ page >
);
}
root. render (< Root />);
import "./styles" ;
import { root } from "@lynx-js/react" ;
import { TagGroup, VStack, useSeedClassName } from "@seed-design/lynx-react" ;
function Root () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< page className = {seedClassName}>
< VStack className = "tag-group-preview" gap = "spacingY.componentDefault" >
< TagGroup.Root tone = "neutralSubtle" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >neutralSubtle</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >3분 전</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
< TagGroup.Root tone = "neutral" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >neutral</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
< TagGroup.Root tone = "brand" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >brand</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >추천</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
</ VStack >
</ page >
);
}
root. render (< Root />);
TagGroupRoot의 tone과 weight은 그룹 기본값으로 전달됩니다. 개별 TagGroupItem에서 필요한 값만 덮어쓸 수 있습니다.
import "./styles" ;
import { root } from "@lynx-js/react" ;
import { TagGroup, useSeedClassName } from "@seed-design/lynx-react" ;
function Root () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< page className = {seedClassName}>
< view className = "tag-group-preview" >
< TagGroup.Root tone = "neutral" className = "tag-group-preview__group" >
< TagGroup.Item tone = "brand" weight = "bold" >
< TagGroup.ItemLabel >NEW</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >무료 나눔</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item tone = "neutralSubtle" >
< TagGroup.ItemLabel >방금 전</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
</ view >
</ page >
);
}
root. render (< Root />);
TagGroupRoot의 separator로 구분 기호를 바꿀 수 있습니다. 의미가 있는 정보는 구분자 대신 TagGroupItem으로 표현하세요.
문자열 구분자의 앞뒤 공백은 Lynx에서 제거됩니다. 예를 들어 separator=" / "와 separator="/"는 동일하게 렌더링되며, 항목과 구분자 사이의 간격은 컴포넌트가 일관되게 적용합니다.
import "./styles" ;
import { root } from "@lynx-js/react" ;
import { TagGroup, VStack, useSeedClassName } from "@seed-design/lynx-react" ;
function Root () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< page className = {seedClassName}>
< VStack className = "tag-group-preview" gap = "spacingY.componentDefault" >
< TagGroup.Root separator = " | " size = "t4" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >가</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >나</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >다</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
< TagGroup.Root separator = " / " size = "t4" className = "tag-group-preview__group" >
< TagGroup.Item >
< TagGroup.ItemLabel >서울</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초구</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >서초4동</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
</ VStack >
</ page >
);
}
root. render (< Root />);
컨테이너 너비를 초과하면 구분자와 뒤따르는 item이 하나의 단위로 다음 줄에 배치됩니다.
import "./styles" ;
import { root } from "@lynx-js/react" ;
import { TagGroup, useSeedClassName } from "@seed-design/lynx-react" ;
function Root () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< page className = {seedClassName}>
< view className = "tag-group-preview" >
< view className = "tag-group-preview__wrapping-container" >
< TagGroup.Root className = "tag-group-preview__wrapping-group" >
< TagGroup.Item >
< TagGroup.ItemLabel >부산광역시 해운대구</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >인증 5회</ TagGroup.ItemLabel >
</ TagGroup.Item >
< TagGroup.Item >
< TagGroup.ItemLabel >3분 전</ TagGroup.ItemLabel >
</ TagGroup.Item >
</ TagGroup.Root >
</ view >
</ view >
</ page >
);
}
root. render (< Root />);
Lynx TagGroup은 Lynx view 엔진(Yoga 기반 flex)의 제약으로 React 웹 버전과 다음과 같은 차이가 있습니다.
슬롯 웹 Lynx Root <span> (inline)<view> (flex-row, flex-wrap, width 100%)Separator <span><text>Item <span> (inline)<view> (flex-row, flex-shrink 0)Item Label <span><text>
웹 : display: inline 기반 text flow. 컨테이너가 좁으면 마지막 item 내부 label text가 word 단위로 자연스럽게 wrap됩니다 (예: "Ut minim laboris enim" → "Ut minim" / "laboris enim" 두 줄로 쪼개짐).
Lynx : flex 기반 item 단위 wrap. item은 content-size를 유지하고, 한 줄에 들어가지 않으면 item 전체가 다음 줄로 이동합니다. item 내부 text가 item 경계를 넘어 word-break되는 동작은 재현할 수 없습니다. Lynx TagGroupRoot는 이를 자연스럽게 보이도록 separator를 뒤따르는 item과 하나의 wrap 단위로 묶어 다음 줄로 함께 이동시킵니다.
웹은 white-space: pre로 문자열 구분자의 앞뒤 공백을 보존합니다. Lynx는 white-space: pre를 지원하지 않고 브라우저 프리뷰와 네이티브 Lynx의 기본 공백 계측도 서로 다릅니다. 두 실행 환경에서 같은 간격을 만들기 위해 Lynx TagGroup은 문자열 구분자의 앞뒤 공백을 제거하고 컴포넌트 스타일의 간격을 적용합니다. 문자열이 아닌 ReactNode 구분자는 변경하지 않습니다.
prop 웹 동작 Lynx 미지원 사유 truncate (Root)한 줄 유지 + 모든 item label의 말줄임 Lynx flex 모델에서는 label이 item 너비에 맞춰지지 않아 웹 수준의 inline ellipsis가 동작하지 않음. 모든 item에 말줄임을 일괄 적용하는 경험이 자연스럽지 않아 제거됨 asChild (Root/Item)Slot 기반 다형 렌더 Lynx에서 Primitive Slot 패턴 미제공 prefixIcon / suffixIcon (Item)아이콘 + 라벨 Lynx 3.7 SVG 지원 이후 Tier B에서 재검토
이벤트: Lynx는 onClick 대신 bindtap / main-thread:bindtap을 사용합니다. TagGroup은 정적 표시 컴포넌트이므로 선택 값이나 비활성화 상태를 관리하는 인터랙션 prop은 노출하지 않습니다.
ref: React.forwardRef로 ref가 전달됩니다 (SVGViewElement 타입으로 캐스트됨).