Notification Badge
아이콘·버튼·메뉴에 붙어 새로운 알림이나 읽지 않은 메시지 수를 나타냅니다. 점과 개수 두 형태가 있습니다.
🚩 Playground
Shape과 Tone, Max, Stroke를 조합해 배지 자체를 확인합니다. 붙는 위치는 컴포넌트가 소유하지 않으므로 여기서는 얹지 않고 배지만 둡니다. Stroke는 배경색과 같은 링이라 한 단계 낮춘 바닥 위에서 보입니다.
Appearance
Elements
Anatomy
Notification Badge를 구성하는 실제 요소와 문서에서 사용하는 명칭입니다. Count를 넘기지 않으면 Container만 남아 원이 됩니다.
Notification Badge structure
- 1.Container
- 2.Count(Optional)
Structure map
Notification Badge
└─ Count (Optional)Properties · Color
Tone은 Accent와 Neutral 둘이며 기본값은 Accent입니다. 채운 형태만 있으므로 Tone마다 배경 하나와 글자 하나뿐이고, Badge와 같은 프리미티브 600단계를 씁니다. Dot은 색으로 뜻을 나눌 여지가 없어 Accent만 제공합니다.
Guidelines
어디에 붙이고 언제 표시하는지 정리합니다.
적절한 Shape 선택하기
둘은 무엇을 말하는지로 갈립니다. 같은 자리에 둘 다 놓을 수 있으므로 자리가 아니라 전달할 정보로 고릅니다.
| Shape | 제공하는 정보 | 쓰는 자리 |
|---|---|---|
Dot | 처리할 것이 있다는 사실만 알립니다. 수를 세게 만들지 않습니다. | 공간이 좁거나 정확한 수가 중요하지 않은 자리입니다. Tone은 Accent 하나뿐입니다. |
Count 12 | Count를 함께 표시해 구체적인 알림 수나 상태 정보를 제공합니다. | 세부 정보가 중요하고 충분한 공간이 있을 때입니다. Max로 표시 폭의 상한을 정합니다. |
붙는 위치는 결합하는 요소에 맞춰 정하기
- 컴포넌트는 모양과 색과 수만 소유합니다. 아이콘·버튼·메뉴 가운데 어디에, 어느 모서리에 달릴지는 화면 코드가 relative와 absolute로 정합니다.
- 컴포넌트가 host를 감싸는 구조를 들고 있으면 쓰려는 자리의 Layout을 건드리게 됩니다. 그래서 위치를 소유하지 않고 className으로 받습니다.
- host와 겹치는 자리에서는 Stroke를 켜서 배경색 링으로 경계를 벌립니다. 링이 없으면 아이콘의 선과 표시의 경계가 붙어 하나로 읽힙니다.
핵심 상태가 있을 때만 표시하기
- 읽지 않은 메시지, 확인되지 않은 알림, 아직 보지 않은 변경사항처럼 사용자가 처리해야 할 상태가 있을 때만 표시합니다.
- 사용자가 그 상호작용을 완료하면 사라집니다. 확인한 뒤에도 표시가 남아 있으면 처리할 것이 남았다는 뜻으로 읽히므로 표시 자체를 믿지 않게 됩니다.
- 상태와 무관한 장식이나 강조에는 쓰지 않습니다. 그 자리는 Badge가 담당합니다.
최대 표시 수를 자리에 맞춰 정하기
- Max는 붙는 자리가 정합니다. 아이콘 모서리처럼 좁은 자리는 99, 목록 행처럼 넓은 자리는 999입니다.
- 넘으면 99+와 999+로 표시합니다. 값을 둘로 제한해 표시 폭이 세 글자와 네 글자로 고정되므로 좁은 자리에서 넘칠 일이 없습니다.
0은 표시하지 않기
- Count가 0이면 컴포넌트가 아무것도 렌더하지 않습니다. 화면 코드가 unread > 0 &&을 쓰지 않아도 됩니다.
- 처리할 것이 없는데 표시가 남으면 사용자가 없는 알림을 찾게 됩니다.
접근 이름은 host 컨트롤이 담당하기
- 수와 뜻은 이 표시가 붙은 host 컨트롤의 접근 이름이 담습니다. 아이콘 버튼이라면 그 버튼의 이름을 「알림 3개」나 「읽지 않은 메시지 3개」로 둡니다.
- 컴포넌트는 수를 텍스트로 렌더할 뿐이고 aria-hidden이나 role=status를 두지 않습니다. 자기가 어디에 붙는지 모르므로 「3」이 무엇의 3인지 말할 수 없습니다.
- host 컨트롤의 이름에 수를 담지 않으면 스크린리더가 「3」만 읽습니다. 붙이는 자리마다 이름을 함께 고칩니다.
남용하지 않기
- 중요한 액션을 유도할 때만 쓰고 그 수를 최소로 유지합니다.
- 한 화면에 여러 개가 놓이면 시각적 피로를 주고 어느 것이 급한지 판단하는 것을 방해합니다. 결국 전부 무시됩니다.
- 우선순위가 높은 자리에만 둡니다. 나머지는 화면 안에서 다른 방식으로 알립니다.
Property map
실제 Props와 기본값입니다. Tone과 Max는 개수 형태에서만 뜻을 가지므로 점에 함께 넘기면 타입에서 걸립니다.
| Property | Values | Default |
|---|---|---|
| count | number | undefined (Dot) |
| max | 99 | 999 | 99 |
| tone | accent | neutral | accent |
| stroke | false | true | true |
| className | string | undefined |
| render | ReactElement | ComponentRenderFn | undefined |
명세 문서
docs/system/components/notification-badge.md
Notification Badge
packages/ui/src/notification-badge.tsx
아이콘·버튼·메뉴 같은 UI 요소에 붙어 새로운 알림이나 읽지 않은 메시지 수를 나타낸다.
역할과 경계
- 사용자가 아직 처리하지 않은 것이 있다는 사실을 표시한다. 읽지 않은 메시지, 확인되지 않은 알림, 아직 보지 않은 변경사항이 그 대상이다.
- 상태와 무관한 보조 정보나 분류, 강조는 badge.md가 담당한다. 두 컴포넌트는 모양이 아니라 표시가 처리할 일을 가리키는지로 갈린다.
- 형태는 둘이며
count의 유무로 갈린다.count가 없으면 8px 원이고, 있으면 높이 18px 알약이다. 18px 은 12px 글자 상자 14px 에 위아래 2px 을 더한 값이며, 한 자리 수에서도 원을 유지하도록 최소 너비를 같은 18px 로 둔다. 원은 「있다」만 말하고 알약은 몇 개인지 말한다. - 크기 단계를 두지 않는다. 두 형태가 8px 과 18px 로 이미 작고, 필요한 단계는 붙는 아이콘 크기에 따라 갈리므로 실제 자리가 나온 뒤에 더한다.
- 자체 interaction 이나 state Property 를 갖지 않는다. 누르는 동작은 이 표시가 붙은 host 컨트롤이 갖는다.
Anatomy
- Container
- Count (Optional)
Notification Badge
└─ Count (Optional)
count 를 넘기지 않으면 Container 만 남아 원이 된다.
Properties
count:number. 없으면 점이고 있으면 개수다.0이하이면 아무것도 렌더하지 않는다max:99 | 999, 기본값99.count를 함께 넘길 때만 받는다tone:accent | neutral, 기본값accent.count를 함께 넘길 때만 받으며 점은accent로 고정한다stroke:boolean, 기본값true. 배경색과 같은 2px 링이다className: 붙는 위치를 받는 자리다. 컴포넌트는 위치를 소유하지 않는다render: 다른 요소로 렌더한다. 누르는 동작을 허용한다는 뜻은 아니다children은 받지 않는다. 내용은count가 정하므로 임의 요소가 들어올 자리가 없다
tone 과 max 는 개수 형태에서만 뜻을 가지므로 점에 함께 넘기면 타입에서 걸린다.
Behavior
count가0이하이면 아무것도 렌더하지 않는다. 그래서 화면 코드가unread > 0 &&을 쓰지 않아도 된다.count가max를 넘으면99+와999+로 표시한다. 표시 폭이 세 글자와 네 글자를 넘지 않는다.- 자체 interaction 이나 state 를 갖지 않는다. Hover·Focus·Active·Disabled 표현이 없고, 누르는 동작과 Focus 표시는 이 표시가 붙은 host 컨트롤이 갖는다.
색
- tone 은
accent와neutral둘이며 기본값은accent다. 알림 표시는 채운 형태만 있으므로 tone 마다 배경 하나와 글자 하나뿐이다. - badge.md의 「색」과 같은 프리미티브 단계 규칙을 쓴다. 배경은 600 단계이고 글자는
white다.
| tone | 배경 | 글자 |
|---|---|---|
accent (기본값) |
red-600 |
white |
neutral |
neutral-600 |
white |
oe-accent-background-bold-primarytoken 을 쓰지 않는다. 그 token 은 Light 에서red-600, Dark 에서red-400이어서 Dark 에서white글자의 대비가 무너진다. 이름은 이 자리를 가리키지만 값이 맞지 않는다.stroke는 배경색과 같은 2px 링이며 기본값은 켜짐이다. host 와 겹치는 자리에서 경계를 벌리는 용도이고, 겹치지 않는 자리에서는 끈다.
Specification
| 자리 | 값 |
|---|---|
| 점 지름 | 8px |
| 개수 높이 | 18px |
| 개수 최소 너비 | 18px |
| 개수 좌우 여백 | 4px |
| 글자 | 12px Medium |
| 모서리 | 완전한 원 |
| 링 | 2px oe-background-primary |
- 개수 높이 18px 은 12px 글자 상자 14px 에 위아래 2px 을 더한 값이다. 최소 너비를 같은 18px 로 두어 한 자리 수에서도 원을 유지한다.
- 수에
tabular-nums를 쓰지 않는다. 등폭 숫자는 열로 늘어놓은 수의 자리를 맞추는 장치인데 이 표시에는 열이 없고, 자릿수가 바뀌면 폭이 어차피 달라진다. 대신1의 advance 가3과 같은 7.5px 로 넓어져19처럼 섞인 수에서 자간이 벌어져 보인다. 비율 숫자에서1은 5.4px 다. 같은 자릿수에서 폭이 최대 2px 흔들리는 것은 감수한다. - 링 색은
oe-background-primary로 고정되어 있다. 다른 Surface 위에 놓는 자리에서는ring-*클래스로 그 Surface 색을 덮어써야 한다. 컴포넌트는 자기가 어느 Surface 위에 있는지 알지 못한다.
Guidelines
적절한 Shape 선택하기
둘은 무엇을 말하는지로 갈린다. 같은 자리에 둘 다 놓을 수 있으므로, 자리가 아니라 전달할 정보로 고른다.
| Shape | 제공하는 정보 | 쓰는 자리 |
|---|---|---|
dot |
처리할 것이 있다는 사실만 알린다. 수를 세게 만들지 않는다. | 공간이 좁거나 정확한 수가 중요하지 않은 자리다. tone 은 accent 하나뿐이다. |
count |
Count 를 함께 표시해 구체적인 알림 수나 상태 정보를 제공한다. | 세부 정보가 중요하고 충분한 공간이 있을 때다. max 로 표시 폭의 상한을 정한다. |
붙는 위치는 결합하는 요소에 맞춰 정하기
- 컴포넌트는 모양과 색과 수만 소유한다. 아이콘·버튼·메뉴 가운데 어디에, 어느 모서리에 달릴지는 화면 코드가
relative와absolute로 정한다. - 컴포넌트가 host 를 감싸는 구조를 들고 있으면 쓰려는 자리의 Layout 을 건드리게 된다. 그래서 위치를 소유하지 않고
className으로 받는다. - host 와 겹치는 자리에서는
stroke를 켜서 배경색 링으로 경계를 벌린다. 링이 없으면 아이콘의 선과 표시의 경계가 붙어 하나로 읽힌다.
핵심 상태가 있을 때만 표시하기
- 읽지 않은 메시지, 확인되지 않은 알림, 아직 보지 않은 변경사항처럼 사용자가 처리해야 할 상태가 있을 때만 표시한다.
- 사용자가 그 상호작용을 완료하면 사라진다. 확인한 뒤에도 표시가 남아 있으면 처리할 것이 남았다는 뜻으로 읽히므로, 표시 자체를 믿지 않게 된다.
- 상태와 무관한 장식이나 강조에는 쓰지 않는다. 그 자리는 badge.md가 담당한다.
최대 표시 수를 자리에 맞춰 정하기
max는 붙는 자리가 정한다. 아이콘 모서리처럼 좁은 자리는99, 목록 행처럼 넓은 자리는999다.- 넘으면
99+와999+로 표시한다. 값을 둘로 제한해 표시 폭이 세 글자와 네 글자로 고정되므로 좁은 자리에서 넘칠 일이 없다.
0은 표시하지 않기
count={0}이면 컴포넌트가 아무것도 렌더하지 않는다. 화면 코드가unread > 0 &&을 쓰지 않아도 된다.- 처리할 것이 없는데 표시가 남으면 사용자가 없는 알림을 찾게 된다.
접근 이름은 host 컨트롤이 담당하기
- 수와 뜻은 이 표시가 붙은 host 컨트롤의 접근 이름이 담는다. 아이콘 버튼이라면 그 버튼의 이름을 「알림 3개」나 「읽지 않은 메시지 3개」로 둔다.
- 컴포넌트는 수를 텍스트로 렌더할 뿐이고
aria-hidden이나role="status"를 두지 않는다. 자기가 어디에 붙는지 모르므로 「3」이 무엇의 3인지 말할 수 없다. - host 컨트롤의 이름에 수를 담지 않으면 스크린리더가 「3」만 읽는다. 붙이는 자리마다 이름을 함께 고친다.
남용하지 않기
- 중요한 액션을 유도할 때만 쓰고 그 수를 최소로 유지한다.
- 한 화면에 여러 개가 놓이면 시각적 피로를 주고 어느 것이 급한지 판단하는 것을 방해한다. 결국 전부 무시된다.
- 우선순위가 높은 자리에만 둔다. 나머지는 화면 안에서 다른 방식으로 알린다.
현재 정의하지 않은 항목
- 크기 단계. 붙는 아이콘 크기에 따라 8px·18px 외의 단계가 필요한지는 실제 자리가 나온 뒤에 본다.
- 링 색을 prop 으로 받을지. 지금은
oe-background-primary로 고정되어 있고 다른 Surface 에서는ring-*클래스로 덮어쓴다. 덮어쓰는 자리가 자주 나오면 Surface 색을 받는 prop 을 두는 편이 낫다.