
lily
A calm, rounded Svelte 5 component library
A copy-paste Svelte 5 component library with a calm, rounded, monochrome design system and a registry-backed CLI.
lily는 Svelte 5를 위한 컴포넌트 라이브러리입니다. 패키지로 설치해 쓰는 대신, CLI로 컴포넌트의 소스 코드를 프로젝트에 직접 복사해 넣고 필요한 대로 고쳐 쓰는 방식입니다. shadcn-svelte와 shadcn-svelte-extras를 바탕으로 출발해, 그 위에 lily만의 디자인 시스템과 CLI를 얹었습니다. 2026년 6월부터 혼자 만들고 있고, lily-svelte라는 이름으로 npm에 배포하고 있습니다.
Calm and Rounded: 조용하고 둥글게
컴포넌트 라이브러리는 보통 많은 색을 준비해 둡니다. 브랜드 색, 보조 색, 상태마다의 색이 단계별로 늘어서고, 그 색들이 화면마다 조금씩 다르게 섞이면서 결국 화면이 시끄러워집니다.
lily는 반대로 덜어내는 데서 출발했습니다. 화면을 이루는 색은 배경, 한 단계 떠 있는 면, 글자 이렇게 세 가지뿐입니다. 흐린 글자, 구분선, 눌린 상태처럼 그 사이의 모든 단계는 글자 색의 투명도로 만듭니다. 그래서 lily로 만든 화면은 어디에 놓여도 조용하고, 다크 모드는 세 가지 색만 바꾸면 끝납니다. 색이 꼭 필요한 차트에만 예외적으로 색을 허용합니다.
선 없이 나누는 면
lily는 카드와 대화상자, 팝오버를 테두리 없이 색만으로 배경과 구분합니다. 이 방식은 두 색의 밝기 차이에 모든 것을 맡깁니다. 차이가 조금만 작아도 떠 있는 면이 배경에 녹아 사라집니다.
처음 라이트 모드의 배경은 #f8f8f8이었습니다. 흰 면과의 밝기 차이가 L* 2.4에 불과해, 카드가 배경에 묻혀 화면이 평평해 보였습니다. 배경을 #f0f0f0으로 낮춰 차이를 5.2로 벌렸고, 다크 모드의 두 색도 같은 차이를 갖도록 맞췄습니다. 그래서 라이트와 다크 어느 쪽에서도 떠 있는 면이 같은 무게로 보입니다.
크기가 아니라 역할로 정한 둥글기
lily의 둥글기는 픽셀 값이 아니라 역할로 정합니다. 콘텐츠를 담는 면이 가장 둥글고, 메뉴와 목록은 한 단계 덜, 그 안의 항목은 그보다 한 단계 덜 둥급니다.
같은 반경이라도 작은 요소에서는 더 둥글어 보이기 때문입니다. 또 바깥 면의 반경이 안쪽 항목의 반경과 여백을 더한 값에 가까워야, 겹쳐진 두 모서리가 같은 중심을 공유하며 자연스럽게 이어집니다. 역할로 반경을 정해 두면 컴포넌트를 어떻게 겹쳐 놓아도 이 관계가 유지됩니다.
누르는 것만 반응한다
lily의 모든 움직임은 살짝 튕기는 하나의 스프링 곡선을 공유합니다. 눌렀을 때 살짝 작아지는 반응은 버튼에만 줍니다. 글 속의 링크나 내비게이션까지 눌릴 때마다 움직이면 화면이 산만해지기 때문입니다.
로딩 중인 버튼은 비활성화하는 대신 “처리 중” 상태로 표시합니다. 비활성화된 버튼은 키보드 포커스를 잃기 때문에, 작업이 끝난 뒤 사용자가 어디에 있었는지 놓치게 됩니다. 스피너는 150ms가 지나서야 나타나 빠른 작업에서 깜빡이지 않고, 글자가 있던 자리는 그대로 유지되어 버튼 크기가 흔들리지 않습니다.
복사해 쓰는 라이브러리의 숙제
소스를 복사해 쓰는 방식의 장점은 코드를 내 것처럼 고칠 수 있다는 것입니다. 단점은 한 번 복사하고 나면 그다음부터는 업데이트를 받기 어렵다는 것입니다. lily의 CLI가 풀어야 했던 것은 대부분 이 숙제였습니다.
고친 것은 지키고, 안 고친 것은 새로
init을 실행하면 CLI는 lily의 디자인 시스템 CSS를 사용자의 스타일시트에 써 넣습니다. 처음에는 한 번 써 넣으면 끝이라, 나중에 디자인 시스템이 바뀌어도 반영할 방법이 없었습니다.
그래서 CLI가 써 넣는 CSS를 시작과 끝 표시로 감싼 하나의 영역으로 만들고, 시작 표시에 버전과 내용의 해시를 함께 기록했습니다. 업데이트할 때 영역의 내용이 해시와 같으면 사용자가 손대지 않은 것이므로 새 버전으로 바꿉니다. 해시와 다르면 사용자가 고친 것이므로 덮어쓰지 않고, 바뀐 줄을 보여 주며 어떻게 할지 묻습니다. 영역 밖에 사용자가 쓴 CSS는 건드리지 않습니다.
shadcn-svelte와 한 프로젝트에서
lily는 처음에 shadcn-svelte와 같은 이름의 설정 파일을 썼습니다. 그래서 이미 shadcn-svelte를 쓰는 프로젝트에 lily를 설치하면, CLI가 shadcn-svelte의 설정을 자기 것으로 읽다가 설치가 중간에 실패했습니다.
설정 파일 이름을 lily.json으로 바꾸고, 예전 이름의 파일은 lily의 것임이 확인될 때만 옮겨 오도록 했습니다. 다른 라이브러리의 설정은 그대로 둡니다. 덕분에 한 프로젝트 안에 두 라이브러리를 함께 두고, 화면 하나씩 lily로 옮겨 갈 수 있습니다.
하나의 소스, 여러 스타일
두 번째 스타일인 Aquamarine을 더하면서, 컴포넌트 코드를 스타일마다 따로 복사해 관리하고 싶지 않았습니다. 그래서 컴포넌트 소스의 클래스 중 스타일에 따라 달라지는 자리에 표시를 남기고, 레지스트리를 빌드할 때 스타일마다 그 자리를 해당 스타일의 클래스로 채우게 했습니다. 기본 스타일에서는 표시만 지웁니다. 어떤 스타일에 채울 값이 빠져 있으면 빌드가 실패하므로, 빠진 자리가 그대로 배포될 일은 없습니다.
사용자가 받는 코드는 이미 스타일이 채워진 평범한 Svelte 코드입니다. 실행 중에 스타일을 고르는 엔진이 없으니 그만큼 가볍습니다. 이미 lily를 쓰고 있는 프로젝트에서 스타일만 바꾸려 하면 CLI가 거절합니다. 이미 복사된 컴포넌트와 디자인 시스템이 서로 다른 스타일로 어긋나지 않게 하기 위해서입니다.
컴포넌트
컴포넌트 구성은 shadcn-svelte를 바탕으로 lily의 디자인 시스템에 맞게 다시 다듬었고, shadcn-svelte-extras의 컴포넌트 일부를 옮겨 왔습니다. 여기에 목록 행, 선택 그룹, 검색 필드, 하단 액션 영역처럼 앱 화면에서 자주 쓰이는 컴포넌트를 lily에서 새로 더했습니다.
lily-pad
lily-pad는 lily로 만든 문서 사이트 생성기입니다. VitePress처럼 마크다운만 쓰면 문서 사이트가 만들어지고, 그 화면은 모두 lily 컴포넌트로 이루어져 있습니다. 검색과 다국어를 지원하고, create-lily-pad로 새 사이트를 바로 시작할 수 있습니다. lily를 직접 써서 무언가를 만들어 보는 첫 번째 사용처이기도 합니다.
lily: Released
lily는 npm의 lily-svelte CLI와 문서 사이트로 공개되어 있고, MIT 라이선스로 누구나 쓸 수 있습니다. SevenWiki의 웹 프론트엔드도 shadcn-svelte에서 lily로 옮겨 왔습니다.