Skip to content

UI v0.20.1 모달고정헤더푸터및배경스크롤잠금 - #37

Merged
youngduck merged 6 commits into
mainfrom
ui-v0.20.1-모달고정헤더푸터및배경스크롤잠금
Jul 21, 2026

Hidden character warning

The head ref may contain hidden characters: "ui-v0.20.1-\ubaa8\ub2ec\uace0\uc815\ud5e4\ub354\ud478\ud130\ubc0f\ubc30\uacbd\uc2a4\ud06c\ub864\uc7a0\uae08"
Merged

UI v0.20.1 모달고정헤더푸터및배경스크롤잠금#37
youngduck merged 6 commits into
mainfrom
ui-v0.20.1-모달고정헤더푸터및배경스크롤잠금

Conversation

@youngduck

Copy link
Copy Markdown
Owner

개요

Modal 컴포넌트를 고도화했습니다. 본문이 길어질 때 제목과 버튼이 함께 스크롤돼 사라지던 문제를 해결하고, 모달이 열린 동안 배경이 스크롤되던 문제도 함께 고쳤습니다.

변경 사항

feat: 모달 고정 헤더/푸터 추가 및 본문 스크롤 분리

  • config.title / config.footer로 상단·하단 영역을 고정하고 가운데 본문(content)만 스크롤
  • Modal을 header / body / footer 3영역으로 재구성
  • bodymin-height:0 + overflow-y:auto로 스크롤 영역 격리 (모달 전체 overflow:hidden)
  • role="dialog"를 backdrop → 모달 박스로 이동, title 지정 시 aria-labelledby 연결 (접근성 보강)
  • 기존 content-only 사용과 하위 호환 유지 (title/footer 미지정 시 종전 동작)

feat: 오버레이 배경 스크롤 잠금 추가

  • useScrollLock 훅 신설 — 모달/다이얼로그가 열린 동안 body 스크롤 잠금
  • 참조 카운팅으로 중첩 오버레이 처리 → 마지막 하나가 닫힐 때만 해제
  • 스크롤바 폭만큼 padding-right 보정으로 배경 밀림(레이아웃 이동) 방지
  • Modal · ConfirmDialog에 적용, Toast는 제외(배경 조작 허용)

docs

  • Storybook: Default 스토리를 title/footer 구조로 정리 + 긴 본문 Sticky 예제 추가
  • docs 사이트 modal.md: title/footer API, 고정 헤더/푸터, 스크롤 잠금, 접근성 섹션 및 API 표 갱신

커밋 구성

  1. feat: 모달고정헤더푸터추가및본문스크롤분리
  2. feat: 오버레이배경스크롤잠금추가
  3. docs: 모달스토리고정헤더푸터예제갱신
  4. docs: 모달문서고정헤더푸터및스크롤잠금반영
  5. chore: v0.20.1버전범프
  6. docs: v0.20.1 CHANGELOG갱신

참고

  • src/styles/token.semantic.css(Tabs 토큰)는 이번 작업과 무관한 별도 변경이라 포함하지 않았습니다.

🤖 Generated with Claude Code

youngduck and others added 6 commits July 21, 2026 12:07
config.title/footer로 상단·하단을 고정하고 가운데 본문만 스크롤되도록
Modal을 header/body/footer 3영역으로 재구성. body에 min-height:0+overflow-y
적용으로 스크롤 영역을 격리하고, role=dialog를 모달 박스로 이동하며
title에 aria-labelledby를 연결해 접근성을 보강. 기존 content-only 사용과
하위 호환 유지.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
모달·다이얼로그가 열려 있는 동안 body 스크롤을 잠그는 useScrollLock 훅 추가.
모듈단위 참조 카운팅으로 중첩 오버레이를 처리해 마지막 하나가 닫힐 때만 해제하고,
사라진 스크롤바 폭만큼 padding-right를 보정해 배경 밀림을 방지. Modal과
ConfirmDialog에 적용(Toast는 배경 조작 허용을 위해 제외).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Default 스토리의 제목·닫기 버튼을 title/footer 영역으로 이동해 정리하고,
긴 본문으로 고정 헤더/푸터 스크롤 동작을 보여주는 Sticky 예제를 추가.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs 사이트 modal.md에 title/footer API, 고정 헤더/푸터 사용법,
배경 스크롤 잠금, 접근성(aria-labelledby) 섹션과 API 표를 갱신.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
yd-ui Ready Ready Preview, Comment Jul 21, 2026 3:10am

@youngduck
youngduck merged commit 680c9fb into main Jul 21, 2026
4 of 6 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces background scroll locking for overlays (such as ConfirmDialog and Modal) using a new useScrollLock hook, and adds support for sticky headers and footers in the Modal component to allow only the body content to scroll. Review feedback suggests optimizing the modal's CSS padding to prevent double-padding issues when both header and footer are present, and replacing useEffect with a safe useLayoutEffect wrapper in useScrollLock to prevent layout flickering on mount.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +22 to +45
/* 상단 고정 영역 (스크롤되지 않음) */
.yds-modal-header {
flex-shrink: 0;
padding: var(--yds-content-padding);
}

.yds-modal-title {
margin: 0;
}

/* 스크롤되는 본문 영역 */
.yds-modal-body {
flex: 1 1 auto;
/* flex 자식이 넘칠 때 스크롤되도록 하는 필수 조건 */
min-height: 0;
overflow-y: auto;
padding: var(--yds-content-padding);
}

/* 하단 고정 영역 (스크롤되지 않음) */
.yds-modal-footer {
flex-shrink: 0;
padding: var(--yds-content-padding);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

📐 모달 헤더/바디/푸터 여백 중첩 개선 (하위 호환성 유지)

현재 설정으로는 titlefooter가 모두 존재할 때, 각각 var(--yds-content-padding) 만큼의 패딩을 가지게 되어 영역 간의 간격이 너무 넓어지는 현상(더블 패딩)이 발생할 수 있습니다.

기존에 content만 단독으로 사용하던 경우의 하위 호환성(사방 패딩 유지)을 보장하면서, 헤더와 푸터가 추가되었을 때 영역 간의 간격을 자연스럽게 조절하기 위해 CSS 인접 형제 선택자(+)와 :not(:last-child) 가상 클래스를 활용하는 방식을 제안합니다.

  /* 상단 고정 영역 (스크롤되지 않음) */
  .yds-modal-header {
    flex-shrink: 0;
    padding: var(--yds-content-padding) var(--yds-content-padding) 0;
  }

  .yds-modal-title {
    margin: 0;
  }

  /* 스크롤되는 본문 영역 */
  .yds-modal-body {
    flex: 1 1 auto;
    /* flex 자식이 넘칠 때 스크롤되도록 하는 필수 조건 */
    min-height: 0;
    overflow-y: auto;
    padding: var(--yds-content-padding);
  }

  /* 헤더가 있을 경우 본문 상단 패딩 조절 (여백 중첩 방지) */
  .yds-modal-header + .yds-modal-body {
    padding-top: calc(var(--yds-content-padding) / 2);
  }

  /* 푸터가 있을 경우 본문 하단 패딩 조절 (여백 중첩 방지) */
  .yds-modal-body:not(:last-child) {
    padding-bottom: calc(var(--yds-content-padding) / 2);
  }

  /* 하단 고정 영역 (스크롤되지 않음) */
  .yds-modal-footer {
    flex-shrink: 0;
    padding: 0 var(--yds-content-padding) var(--yds-content-padding);
  }

@@ -0,0 +1,44 @@
import { useEffect } from 'react'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

⚡ SSR 대응 및 레이아웃 흔들림 방지를 위한 useLayoutEffect 도입

useEffect는 브라우저가 화면을 그린(paint) 후에 비동기적으로 실행되므로, 모달이 열릴 때 아주 잠깐 스크롤바가 보였다가 사라지면서 레이아웃이 미세하게 흔들리는 현상(Flicker)이 발생할 수 있습니다.

화면을 그리기 전에 동기적으로 스크롤을 잠그기 위해 useLayoutEffect를 사용하는 것이 좋습니다. 다만, SSR(Server-Side Rendering) 환경에서 useLayoutEffect를 그대로 사용하면 경고가 발생하므로, 환경에 따라 안전하게 대체되는 useSafeLayoutEffect 패턴을 제안합니다.

import { useEffect, useLayoutEffect } from 'react'

const useSafeLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect

Comment on lines +17 to +18
export function useScrollLock() {
useEffect(() => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

정의한 useSafeLayoutEffect를 사용하여 브라우저가 화면을 그리기 전에 스크롤 잠금 및 패딩 보정이 동기적으로 적용되도록 합니다.

Suggested change
export function useScrollLock() {
useEffect(() => {
export function useScrollLock() {
useSafeLayoutEffect(() => {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant