lifecarelog
프론트엔드

블롭·일러스트 없이 빈 화면 채우기: 데코 없는 empty state 컴포넌트

데코 금지 브랜드에서 그림 없이 빈 목록 화면을 설계하는 법. 상태 3종 분리, 3조각 컴포넌트, 틴트·1px 보더·8px 간격으로 채우는 구현을 정리해요.

5분 읽기

빈 목록이 뜨는 순간, 손이 자꾸 일러스트로 가요. 둥근 블롭 하나, 빈 상자 그림 하나 얹으면 허전함이 사라지니까요. 그런데 데코를 아예 금지한 브랜드 규칙 아래서 플랜비(plan-b)의 멤버·회비 화면을 만들다 보니, 그림 없이도 빈 화면이 충분히 설명적일 수 있더라고요. 그 구현 방식을 정리해 볼게요.

빈 화면은 하나가 아니에요

직접 만들어 보니 "비어 있음"은 최소 3가지로 갈라져요. 아직 아무것도 없는 초기 빈 상태, 필터 때문에 결과가 0건인 필터 빈 상태, 요청이 실패한 오류 상태예요. 셋을 한 컴포넌트로 뭉개면 "멤버가 없어요"라는 문구가 필터 걸린 화면에도 떠서, 사용자는 데이터가 사라진 줄 알아요. 그래서 variant 하나로 갈라 두고 문구와 버튼을 각각 받게 했어요.

초기 빈 상태 · 필터 빈 상태 · 오류 상태 — 문구와 버튼이 어떻게 달라지는지

컴포넌트는 세 조각이면 돼요

제목, 설명 한 줄, 버튼 1개. 이 셋만 받아요. 버튼을 여러 개 받도록 열어 두면 나중에 꼭 "취소"나 "더 알아보기"가 붙어서 빈 화면이 메뉴판이 돼요. 화면당 CTA 1개라는 규칙을 props 타입으로 못 박아 두는 편이 마음 편했어요.

type EmptyStateProps = {
  variant: "initial" | "filtered" | "error";
  title: string;
  description: string;
  action: { label: string; onClick: () => void };
};
 
export function EmptyState({ title, description, action }: EmptyStateProps) {
  return (
    <section role="status" className="empty-state">
      <h2>{title}</h2>
      <p>{description}</p>
      <button type="button" onClick={action.onClick}>{action.label}</button>
    </section>
  );
}

role="status"를 붙여 두면 목록이 비는 순간 스크린리더가 문구를 읽어 줘요. 텍스트가 주인공이라 접근성은 오히려 챙기기 쉬웠어요.

허전함은 여백과 면으로 메워요

데코를 걷어내면 남는 건 배경 틴트, 둘레 1px 보더, 간격이에요. 적용해 봤더니 이 세 가지만으로 "여기가 비어 있는 자리"라는 게 분명해졌어요.

.empty-state {
  padding: 48px 24px;
  border: 1px solid color-mix(in oklch, var(--color-on-surface) 12%, transparent);
  background: color-mix(in oklch, var(--color-primary) 4%, var(--color-surface));
  text-align: left;
}
.empty-state h2 + p { margin-top: 8px; }
.empty-state p + button { margin-top: 24px; }

간격은 전부 8px 배수예요. 제목과 설명 사이 8px, 설명과 버튼 사이 24px. 테스트해 보면 13px 같은 임의값이 하나만 섞여도 화면이 묘하게 어색해져요. 배경은 브랜드색을 4%만 섞어 강조가 아니라 영역으로 읽히게 했고, 가운데 정렬 대신 왼쪽 정렬로 본문 톤과 맞췄어요.

  • 둘레 1px 보더
  • 브랜드색 4% 틴트
  • 8px 배수 간격
  • 버튼 1개

레이아웃 흔들림도 같이 잡아요

빈 화면을 목록과 다른 자리에 렌더링하면 데이터가 들어오는 순간 화면이 튀어요. 돌려 보니 리스트 컨테이너 안에 그대로 넣고 min-height를 목록 3행 높이로 맞추는 게 제일 단순했어요. 로딩 스켈레톤도 같은 높이를 쓰니 로딩, 빈 상태, 데이터 순서로 바뀔 때 점프가 사라졌어요.

정리

그림을 못 쓴다는 제약이 처음엔 손발을 묶는 것 같았는데, 결과적으로 문구를 더 고민하게 만들었어요. "멤버가 없어요"보다 "첫 멤버를 초대해 보세요"가 낫고, 버튼은 그 문장의 동사를 그대로 받아요. 빈 화면에 필요한 건 채우는 그림이 아니라 다음 행동 하나예요.

#empty-state#React#UI 컴포넌트

라이프케어로그 서비스가 궁금하신가요?

AI 기반 건강·일정·재활 관리 앱을 직접 써보세요.

서비스 살펴보기

관련 글

댓글

아직 댓글이 없어요. 첫 댓글을 남겨주세요.