# 칩

태그와 필터에 쓰는 알약이에요. 주소가 있으면 링크, 없으면 라벨이에요.

- Type: component
- Theme: base
- Tags: arc, component, chip, tag, filter, pill, link
- English title: Chip
- URL: https://dsui.vercel.app/items/chip

## Controls

| Key | Type | Label | Default |
| --- | --- | --- | --- |
| label | text | 문구 | 컴포넌트 |
| size | select | 크기 | md |
| count | slider | 개수 | 12 |
| current | boolean | 현재 항목 | false |

## Source

### chip.module.css

```css
.list { display: flex; flex-wrap: wrap; margin: 0; padding: 0; gap: var(--space-2); list-style: none; }
.chip { display: inline-flex; min-height: var(--control-height-sm); align-items: center; gap: var(--space-1); border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 0 14px; background: var(--surface); color: var(--text-secondary); font-size: var(--text-sm); font-weight: 500; line-height: 20px; text-decoration: none; white-space: nowrap; }
.sm { min-height: 26px; padding: 0 10px; font-size: var(--text-xs); }
/* The number is context, not the label, so it stays a step quieter than the word it follows. */
.count { color: var(--text-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.link { -webkit-tap-highlight-color: transparent; transition: color var(--duration-fast) var(--ease-standard), background var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard), transform var(--duration-fast) var(--ease-standard); }
@media (hover: hover) and (pointer: fine) {
  .link:hover { border-color: var(--border-strong); color: var(--foreground); }
}
.link:active { background: var(--surface-muted); border-color: transparent; color: var(--foreground); transform: scale(.97); }
/* The current filter is told apart by a filled face and a stronger edge, not by color alone. */
.link[aria-current="true"] { border-color: transparent; background: var(--accent-subtle); color: var(--foreground); }
.link[aria-current="true"] .count { color: var(--accent); }
@media (hover: hover) and (pointer: fine) {
  .link[aria-current="true"]:hover { border-color: transparent; background: var(--accent-subtle); }
}
@media (prefers-reduced-motion: reduce) { .link { transition: none; } .link:active { transform: none; } }

```

### chip.tsx

```tsx
"use client";

import type { HTMLAttributes, ReactNode } from "react";
import { ArcLink } from "../lib/arc-provider";
import { playUiSound } from "../sound/play";
import styles from "./chip.module.css";

export type ChipSize = "sm" | "md";

export interface ChipProps {
  /** Makes the chip a link. Without it the chip is a plain label. */
  href?: string;
  /** Marks the filter the reader is on. Only meaningful with `href`. */
  current?: boolean;
  size?: ChipSize;
  /** A quiet number after the label, such as how many items a tag holds. */
  count?: number | string;
  /** The language of the label, when it differs from the page. */
  lang?: string;
  className?: string;
  children: ReactNode;
}

/**
 * A pill for a tag or a filter. With `href` it goes somewhere; without one it is a label and gets no hover or press,
 * because nothing happens when you touch it. For chips that are *chosen* rather than followed — a filter that changes
 * the list in place — use ChipGroup, which keeps selection and arrow-key movement.
 */
export function Chip({ href, current = false, size = "md", count, lang, className, children }: ChipProps) {
  const classes = [styles.chip, styles[size], className].filter(Boolean).join(" ");
  const content = (
    <>
      {children}
      {count === undefined ? null : <span className={styles.count}>{count}</span>}
    </>
  );
  if (!href) {
    return <span className={classes} lang={lang}>{content}</span>;
  }
  return (
    <ArcLink
      href={href}
      lang={lang}
      className={[classes, styles.link].join(" ")}
      aria-current={current ? "true" : undefined}
      onClick={() => playUiSound("tick")}
    >
      {content}
    </ArcLink>
  );
}

export interface ChipListProps extends HTMLAttributes<HTMLUListElement> {
  /** The accessible name of the row, e.g. "태그". */
  label?: string;
  children: ReactNode;
}

/** A wrapping row of chips as a real list, so a screen reader announces how many there are. Wrap each Chip in an `<li>`. */
export function ChipList({ className, label, children, ...props }: ChipListProps) {
  return (
    <ul {...props} aria-label={label} className={[styles.list, className].filter(Boolean).join(" ")}>
      {children}
    </ul>
  );
}

Chip.displayName = "Chip";
ChipList.displayName = "ChipList";

export default Chip;

```
