@olundot/ui · Feedback
Spinner
진행률을 알 수 없는 짧은 대기에 쓰는 비결정 로딩 인디케이터입니다.
- 크기
- sm (16px) · md (24px, 기본) · lg (32px)를 사용합니다.
- 접근성
- role=status + aria-label 필수 (기본: '로딩 중')
- 배치
- 인라인(size=sm) · 블록(size=md) · 오버레이
- Button 통합
- 버튼 안의 로딩은 Button loading prop으로 처리하고, Button 옆에 별도 Spinner를 중복 배치하지 않습니다.
- 애니메이션
- spin (prefers-reduced-motion → pulse로 대체)
기본
크기별 로딩 상태와 접근성 label코드 보기tsx
import { Spinner } from "@olundot/ui";
// Spinner는 <span role="status" aria-label="로딩 중" />을 기본으로 렌더링.
// label prop으로 접근성 텍스트를 맥락에 맞게 변경.
// size: "sm" (16px) · "md" (24px, 기본) · "lg" (32px)
export function SpinnerBasic() {
return (
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Spinner size="sm" label="소형 로딩 중" />
<Spinner size="md" label="기본 로딩 중" />
<Spinner size="lg" label="대형 로딩 중" />
</div>
);
}인라인
짧은 행 상태에는 작은 스피너 배치제출 처리 중...
자동 저장 중
코드 보기tsx
import { Spinner } from "@olundot/ui";
export function SpinnerInline() {
return (
<div style={{ display: "grid", gap: "12px" }}>
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
<Spinner size="sm" label="제출 중" />
<span>제출 처리 중...</span>
</div>
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
<Spinner size="sm" label="저장 중" />
<span style={{ fontSize: "0.875rem", color: "var(--text-secondary)" }}>
자동 저장 중
</span>
</div>
</div>
);
}Button loading 통합
Button loading 상태와 함께 사용코드 보기tsx
import { useState } from "react";
import { Button } from "@olundot/ui";
// Button 자체의 loading 상태를 사용하면 버튼 레이블과 로딩 표현을 한곳에서 관리할 수 있습니다.
// 별도 Spinner를 Button 옆에 두는 패턴 대신 이 방식을 권장합니다.
export function SpinnerToggle() {
const [loading, setLoading] = useState(false);
return (
<div style={{ display: "flex", gap: "12px", alignItems: "center" }}>
<Button
loading={loading}
onClick={() => {
setLoading(true);
setTimeout(() => setLoading(false), 2000);
}}
>
{loading ? "처리 중..." : "작업 시작"}
</Button>
</div>
);
}