컴포넌트

Icon Button

아이콘으로 작업을 실행합니다.

설치

pnpm dlx ply-ui add icon-button

공통 설치 설정을 먼저 적용합니다.

사용법

iconaria-label을 함께 지정합니다. aria-label에는 아이콘 모양이 아니라 실행할 작업 이름을 적습니다. 기본 종류는 emphasis, 기본 크기는 lg입니다.

icon에는 Roblox 아이콘 이름 외에 <Minus /> 같은 SVG 아이콘 컴포넌트도 전달할 수 있습니다. 다른 아이콘팩 사용을 참고하세요.

Emphasis

variant="emphasis" — 강조 색상으로 주요 작업을 표시합니다. 기본값입니다.

Standard

variant="standard" — 중립 색상의 배경으로 일반 작업을 표시합니다.

Alert

variant="alert" — 삭제와 같은 위험한 작업을 표시합니다.

Utility

variant="utility" — 배경 없이 아이콘을 표시합니다.

Over media

variant="over-media" — 배경 위에서 아이콘 버튼을 표시합니다. Button의 같은 이름 속성과는 다른 색상 토큰을 사용합니다.

원형

circular를 지정하면 모서리가 원형으로 바뀝니다. 기본값은 false입니다.

비활성

disabled로 조작을 막습니다. 작업 이름을 설명하는 aria-label은 그대로 유지합니다.

크기

sizexs, sm, md, lg이며 기본값은 lg입니다. 아이콘 크기도 각각 16, 20, 24, 28px로 바뀝니다.

선택 상태

selectedutility 종류의 배경을 바꿉니다. 선택 상태는 직접 관리하고 aria-pressed도 함께 연결합니다.

속성

이 프로젝트에서 추가하거나 제한한 속성입니다.

IconButton

속성

타입

구현 코드

components/ui/icon-button.tsx
icon-button.tsx
"use client";
import type { ComponentProps, ReactElement } from "react";
import { Button as Primitive } from "@base-ui/react/button";
import { withClassName } from "../../lib/cx";
import { Icon, type IconName } from "./icon";
import "./icon-button.css";
export type IconButtonProps = Omit<
  ComponentProps<typeof Primitive>,
  "children"
> & {
  /** 스크린 리더가 읽을 작업 이름입니다. */
  "aria-label": string;
  /** Roblox 아이콘 이름 또는 다른 아이콘팩의 SVG 요소입니다. */
  icon: IconName | ReactElement;
  /** 버튼 높이와 아이콘 크기입니다. @defaultValue "lg" */
  size?: "xs" | "sm" | "md" | "lg";
  /** 버튼의 색상과 강조 수준입니다. @defaultValue "emphasis" */
  variant?: "emphasis" | "standard" | "alert" | "utility" | "over-media";
  /** 원형으로 표시합니다. @defaultValue false */
  circular?: boolean;
  /** 선택한 상태의 스타일을 적용합니다. @defaultValue false */
  selected?: boolean;
};
/** 아이콘 전용 버튼은 텍스트 Button과 glyph 크기/utility 배경 규칙이 다릅니다. */
export function IconButton({
  icon,
  size = "lg",
  variant = "emphasis",
  circular = false,
  selected = false,
  className,
  ...props
}: IconButtonProps) {
  return (
    <Primitive
      {...props}
      data-size={size}
      data-variant={variant}
      data-circular={circular || undefined}
      data-selected={selected || undefined}
      className={withClassName("rbx-icon-button", className)}
    >
      {typeof icon === "string" ? (
        <Icon name={icon} size={{ xs: 16, sm: 20, md: 24, lg: 28 }[size]} />
      ) : (
        <Icon render={icon} size={{ xs: 16, sm: 20, md: 24, lg: 28 }[size]} />
      )}
    </Primitive>
  );
}
components/ui/icon-button.css
icon-button.css
.rbx-icon-button {
  width: 48px;
  height: 48px;
  min-height: 48px;
  padding: 0;
  border: 0;
  background-color: var(--rbx-color-action-emphasis-background);
  color: var(--rbx-color-action-emphasis-foreground);
}
.rbx-icon-button[data-size="md"] {
  width: 40px;
  height: 40px;
  min-height: 40px;
}
.rbx-icon-button[data-size="sm"] {
  width: 32px;
  height: 32px;
  min-height: 32px;
}
.rbx-icon-button[data-size="xs"] {
  width: 24px;
  height: 24px;
  min-height: 24px;
  border-radius: 4px;
}
.rbx-icon-button[data-circular] {
  border-radius: 9999px;
}
.rbx-icon-button[data-variant="standard"] {
  background-color: var(--rbx-color-action-standard-background);
  color: var(--rbx-color-action-standard-foreground);
}
.rbx-icon-button[data-variant="alert"] {
  background-color: var(--rbx-color-action-alert-background);
  color: var(--rbx-color-action-alert-foreground);
}
.rbx-icon-button[data-variant="utility"] {
  background-color: var(--rbx-color-action-link-background);
  color: var(--rbx-color-content-emphasis);
}
.rbx-icon-button[data-variant="utility"][data-selected] {
  background-color: var(--rbx-color-shift-300);
}
.rbx-icon-button[data-variant="over-media"] {
  background-color: var(--rbx-color-over-media-0);
  color: var(--rbx-color-content-emphasis);
}
.rbx-icon-button:is(:disabled, [data-disabled]):is(
    [data-variant="emphasis"],
    [data-variant="alert"]
  ) {
  background-color: var(--rbx-color-action-standard-background);
  color: var(--rbx-color-action-standard-foreground);
}

목차