2026-09-10: 설명과 코드 예시를 보완했습니다. 아래 예시는 글의 설계 의도를 전달하기 위한 것이며, 원 프로젝트에 반영된 변경 내역과는 구분합니다.
긴 설명을 테이블 셀에 전부 넣으면 한눈에 훑기 어렵고, 잘라놓기만 하면 필요한 내용을 읽을 수 없다. 평소에는 짧게 보여주고 누르면 전체를 여는 컴포넌트를 만들었다. 이름은 Magnifying. 필요할 때 확대경을 대보자는 뜻이다.
핵심은 내용을 그리는 함수를 받는 구조다. 같은 데이터에서 요약과 상세를 만들되, 지금 어느 쪽을 보여주는지에 따라 모양을 바꿀 수 있게 하려 했다.
처음 예시에서는 렌더 함수의 결과를 useRef에 보관했다. 그러면 이후 데이터가 바뀌어도 처음 만든 화면이 남는다. 클릭 대상을 ref와 정확히 비교하는 방식도 내부 요소를 눌렀을 때 동작하지 않는 문제가 있었다.
그래서 예시를 두 군데 바꿨다. 렌더 결과는 매번 계산하고, 상세 화면은 명시적인 버튼으로 연다.
요약과 상세를 같은 데이터에서 만들기
아래 Dialog는 프로젝트의 다이얼로그 컴포넌트다. open, onClose, children을 받으며, 접근 가능한 이름, 초점 이동·복귀, 키보드 닫기와 배경 상호작용 차단을 제공한다고 가정한다. 이 글에서는 테이블 셀의 렌더링 계약에 집중한다.
import { useState, type ReactNode } from 'react';
import { Dialog } from './Dialog';
type MagnifyingProps = {
label: string;
renderContent: (mode: 'summary' | 'detail') => ReactNode;
};
export function Magnifying({ label, renderContent }: MagnifyingProps) {
const [open, setOpen] = useState(false);
return (
<>
<button
type="button"
aria-label={label}
aria-haspopup="dialog"
onClick={() => setOpen(true)}
style={{ maxWidth: '100%', textAlign: 'left' }}
>
{renderContent('summary')}
</button>
<Dialog open={open} onClose={() => setOpen(false)}>
{open && renderContent('detail')}
<button type="button" onClick={() => setOpen(false)}>닫기</button>
</Dialog>
</>
);
}
사용처에서는 현재 값을 렌더 함수에 전달한다.
function DescriptionCell({ text }: { text: string }) {
return (
<Magnifying
label="설명 전체 보기"
renderContent={(mode) => mode === 'detail' ? (
<p style={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }}>{text}</p>
) : (
<span style={{
display: 'block',
maxWidth: 200,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}>
{text}
</span>
)}
/>
);
}
text가 바뀌면 요약과 열린 상세 화면 모두 새 값으로 렌더링된다. ref로 이전 JSX를 고정하지 않는다. 버튼 내부의 span을 눌러도 클릭 이벤트가 버튼으로 전달되고, 키보드로도 열 수 있다.
요약은 버튼 안에 들어가므로 링크나 또 다른 버튼을 포함하지 않는 콘텐츠여야 한다. 복잡한 셀이라면 요약 콘텐츠 옆에 별도의 상세 보기 버튼을 두는 편이 적절하다. 테이블 행 클릭 이벤트가 있다면 행 동작과 버튼 동작의 관계도 사용처에서 정해야 한다.
읽기용 상세 보기에 맡길 일
요약과 상세가 데이터를 공유한다는 계약은 남기고, 임의 요소 복제와 클릭 대상 추론은 줄였다. 상세 화면 안에 편집 상태가 있다면 닫을 때 초기화할지 유지할지는 추가로 정해야 한다. 이 예시는 읽기용 상세 보기를 대상으로 한다.
사용처는 같은 데이터로 요약과 상세를 어떻게 그릴지 정하고, Magnifying은 두 화면을 오가는 일을 맡는다. 텍스트든 이미지든 읽기용 미리보기에 적용해볼 수 있는 구조다. 테이블에 모든 것을 펼쳐놓을 필요는 없지만, 잘라놓은 내용은 필요할 때 들여다볼 수 있어야 하니까.
Assisted by AI
© uiwwsw · 본인 소유의 글·이미지에 대한 무단 복제·재게시를 허용하지 않습니다. 개인 열람·원문 링크 공유·검색 색인과 제한적인 미리보기는 허용합니다. 법령상 이용 예외, 기존 이용 허락, 코드·제삼자 자료의 기존 라이선스는 유지합니다. 콘텐츠 이용 안내