컴포넌트
Icon Button
아이콘으로 작업을 실행합니다.
설치
pnpm dlx ply-ui add icon-button공통 설치 설정을 먼저 적용합니다.
사용법
icon과 aria-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은 그대로 유지합니다.
크기
size는 xs, sm, md, lg이며 기본값은 lg입니다. 아이콘 크기도 각각 16, 20, 24, 28px로 바뀝니다.
선택 상태
selected는 utility 종류의 배경을 바꿉니다. 선택 상태는 직접 관리하고 aria-pressed도 함께 연결합니다.
속성
이 프로젝트에서 추가하거나 제한한 속성입니다.
IconButton
구현 코드
components/ui/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
.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);
}