00:00:00Radix UI는 이제 그만 쓰고 새로운 라이브러리로 갈아타세요. 바로 Base UI인데요, 사실 여러분이 shadcn/ui 팬이라면
00:00:06이미 전환할 수 있는 선택지가 마련되어 있습니다. 아직 Base UI에 대해 들어본 적이 없으시다면,
00:00:10이곳은 Radix, Floating UI, Material UI를 만든 원년 멤버들이 모여 만든 헤드리스 UI 라이브러리입니다.
00:00:15컴포넌트의 기능과 웹 접근성은 라이브러리가 챙겨주되, 디자인은 여러분이 직접 입히는 방식이죠.
00:00:20LLM(거대언어모델)이 아직 예외 케이스나 접근성 요구사항을 완벽히 처리하지 못하는 요즘 같은 시대에 특히 중요합니다.
00:00:24하지만 제가 방금 설명한 특징은 사실 Radix와 정확히 일치합니다.
00:00:30그렇다면 왜 굳이 새 라이브러리가 필요할까요? 바로 본론으로 들어가서 주요 차이점을 보여드리겠습니다.
00:00:35먼저 Base UI 공식 문서를 빠르게 살펴보면서 왼쪽 메뉴에 있는
00:00:44다양한 컴포넌트들을 확인해 보겠습니다. 컴포넌트 라이브러리에 필요한 거의 모든 요소가 갖춰져 있고,
00:00:48심지어 Radix에는 없는 콤보 박스(Combo Box) 같은 고급 컴포넌트도 제공합니다.
00:00:52모든 컴포넌트에는 깔끔한 예시가 포함되어 있어 어떻게 구현하고 스타일링하는지 알 수 있는데,
00:00:57CSS 모듈은 물론 원한다면 테일윈드(Tailwind) 예시로 바꿔서 볼 수도 있습니다.
00:01:01문서도 정말 훌륭하지만, 오늘은 문서를 비교하러 온 게 아니니 첫 번째 핵심 차이점으로 바로 넘어가 보죠.
00:01:06아마 여러분이 가장 많이 듣게 될 이야기는 바로 이것일 겁니다.
00:01:10Base UI는 활발하게 유지보수되고 있는 반면, Radix는 일종의 “좀비 상태”라는 점이죠.
00:01:15GitHub 기여 차트를 보면 Base UI는 꾸준히 성장하고 있지만, Radix는
00:01:20이따금씩 커밋이 올라오는 정도입니다. 최근 한 달간 처리된 PR과 이슈를 보면
00:01:25그 차이가 더 명확해집니다.
00:01:29Base UI는 58개의 이슈를 해결하고 154개의 PR을 머지한 반면, Radix는 단 한 개의 이슈도, PR도 처리하지 않았습니다.
00:01:36Radix에 무슨 일이 있었는지 요약하자면, WorkOS라는 회사가 Radix의 제조사를 인수했는데
00:01:42Radix 자체에는 투자를 거의 하지 않았습니다. 그래서 팀원 대부분이 떠났고 지금의 상태가 된 거죠.
00:01:47심지어 Radix의 공동 제작자는 “마지막 수단이 아니면 Radix를 쓰지 않겠다”라고 말했고, 그는 현재
00:01:53Base UI 팀에서 일하고 있습니다. 따라서 미래에 해결되지 않을 버그로 고생하지 않으려면
00:01:58활발히 관리되는 의존성을 사용하는 것이 중요합니다.
00:02:02더 좋은 점은 Base UI가 Radix와 매우 비슷하게 설계되어 마이그레이션이 어렵지 않다는 것입니다.
00:02:08물론 그 와중에 개선된 부분들도 숨어 있는데요, 제가 가장 좋아하는 개선점 중 하나는
00:02:13Radix의 “asChild” 프롭을 처리하는 방식입니다. 혹시 이게 생소하신 분들을 위해
00:02:17여기 Radix Select 컴포넌트를 준비했습니다. 제가 만든 커스텀 컴포넌트를
00:02:22Select의 트리거로 렌더링하고 싶을 때, 단순히 트리거 컴포넌트로 감싸기만 하면
00:02:27불필요한 래퍼(wrapper) 컴포넌트가 생기고 그 안에 “구독” 버튼이 들어가게 됩니다. (구독 꼭 눌러주세요!)
00:02:31하지만 이 구독 버튼 자체가 곧바로 Select 트리거 역할을 하게 만들고 싶다면,
00:02:36Radix에서는 트리거에 “asChild” 프롭을 추가하면 됩니다. 그러면 Radix는
00:02:41트리거의 모든 속성과 기능을 그 자식으로 전달된 컴포넌트와 병합하게 됩니다.
00:02:46실제로 클래스 이름이 버튼과 병합되는 것을 볼 수 있습니다. 여기서는 덮어씌워지고 있네요.
00:02:50이제 프롭을 지우고 저장해 보면 버튼 하나만 남지만,
00:02:55기능적으로는 여전히 Select 트리거 역할을 수행합니다.
00:03:00매우 유용한 기능이지만, 코드가 명시적이지 않다는 불만이 꽤 있었습니다.
00:03:04솔직히 저도 코드를 훑어볼 때 이 프롭을 놓쳐서 문제의 원인을 찾지 못할 때가 종종 있었거든요.
00:03:09이제 Base UI에서는 이 작업을 어떻게 하는지 보겠습니다. 기능은 똑같습니다.
00:03:13여기 Select 트리거 역할을 하는 버튼이 있는데, 코드를 보시면
00:03:18Base UI는 “asChild” 대신 “render” 프롭을 사용합니다.
00:03:24이 “render” 프롭에 렌더링하고 싶은 컴포넌트를 직접 지정하는 방식이죠.
00:03:29사소한 변화처럼 보일 수 있지만, 무엇을 하려는지 훨씬 더 명시적이라고 생각합니다.
00:03:34이 컴포넌트를 렌더링한다고 말 그대로 써져 있으니까요. 자식 컴포넌트를 쓰는지,
00:03:39“asChild” 프롭이 있는지 일일이 찾아볼 필요가 없습니다. 아주 작지만 좋은 변화라고 봅니다.
00:03:43이 “render” 프롭의 진가는 여기서 끝이 아닙니다.
00:03:48Switch 컴포넌트를 만들 때 보면, “render” 프롭에 함수를 전달할 수도 있습니다.
00:03:52덕분에 우리가 만들고 있는 컴포넌트의 상태값에 직접 접근할 수 있게 되죠.
00:03:56이 Switch Thumb 예시처럼, 전달받은 프롭을 어떤 컴포넌트에 적용할지 선택할 수 있고,
00:04:01컴포넌트의 상태에 따라 커스텀 렌더링이나 스타일링 로직을 짤 수도 있습니다.
00:04:05상태값에는 체크 여부(checked), 변경 여부(dirty), 비활성화 여부(disabled) 등 수많은 정보가 포함됩니다.
00:04:10여기서는 단순히 체크 상태인지 확인해서
00:04:14상황에 맞는 서로 다른 아이콘을 렌더링하고 있습니다.
00:04:18심지어 여러분만의 커스텀 컴포넌트에 이 “render” 프롭 기능을 넣어주는 훅(hook)도 존재합니다.
00:04:22조금 고급 내용이긴 하지만, 여러분이 원하는 어떤 커스텀 기능이든 Base UI로 구현 가능하다는 걸 보여드리고 싶었습니다.
00:04:27다시 Select 컴포넌트로 돌아와서, 다음 차이점은 Base UI가 데이터 기반(data-driven) 방식을 지원한다는 점입니다.
00:04:31먼저 Radix Select 코드를 보시죠. 라벨과 밸류가 담긴 배열이 있고,
00:04:35이 값들을 Select 안에 넣으려면 단순히 해당 배열을 map으로 돌려서
00:04:40Radix의 Select Item 컴포넌트를 렌더링하면 됩니다. 그러면 이렇게 값이 들어가죠.
00:04:44이제 Base UI 방식을 보면 굉장히 비슷해 보입니다. 여전히 상단에 배열이 있고
00:04:49하단에서 map을 돌려 Select Item을 렌더링하고 있죠. 하지만 한 군데 더 추가된 곳이 있는데,
00:04:54바로 이 Select Root 부분입니다. 여기에 해당 배열을 전달해 줍니다.
00:04:59이것은 미묘하지만 중요한 차이를 만듭니다. 컴포넌트가 렌더링되기 전에 어떤 데이터를 그릴지 미리 알게 된다는 뜻이죠.
00:05:03이는 특히 서버 사이드 렌더링(SSR) 시 성능 향상에 도움이 됩니다.
00:05:08다만 개인적으로 개선되었으면 하는 점은, 현재 “items” 프롭으로 배열을 넘기면서도
00:05:13하단에서 다시 한번 map을 돌리고 있다는 점입니다. 데이터를 두 번 쓰는 셈이죠.
00:05:17대신 또 다른 헤드리스 라이브러리인 React Aria처럼 구현하면 좋을 것 같습니다.
00:05:22React Aria는 배열을 부모 요소에 넘긴 뒤, 그 자식으로는 함수를 사용합니다.
00:05:26그러면 부모로부터 전달된 데이터를 함수가 알아서 처리하므로 배열을 두 번 쓸 필요가 없죠.
00:05:32부모가 데이터 제공자 역할을 하는 셈인데, 이 방식이 더 낫다고 봅니다.
00:05:36그래도 다시 Select 컴포넌트로 돌아가서 또 다른 차이점을 보여드리고 싶은데요,
00:05:41방금 본 “render” 프롭이나 데이터 기반 방식은 거의 모든 컴포넌트에 해당되지만,
00:05:45이번에는 Select 컴포넌트만의 특징입니다. 바로 멀티 셀렉트(Multi-select)가 가능하다는 것입니다.
00:05:50Radix에서 정말 뼈아프게 부족했던 기능이죠.
00:05:55Base UI에서는 Select Root에 “multiple” 프롭을 추가하기만 하면 됩니다.
00:05:59그러면 아주 쉽게 멀티 셀렉트 기능이 활성화됩니다. 정말 간단하죠?
00:06:03한 걸음 더 나아가, Base UI는 Radix에 없던 콤보 박스나 오토 컴플릿(Auto Complete) 같은 컴포넌트도 갖추고 있습니다.
00:06:08활발히 유지보수되는 덕분에 사용자들의 요청에 즉각 대응할 수 있는 것이죠.
00:06:13Radix와 Base UI의 차이점 두 가지만 더 보여드리겠습니다. Select가 좀 지겨우니
00:06:17체크박스 컴포넌트로 바꿔서 설명해 드릴게요.
00:06:22첫 번째는 스타일링에 관한 것입니다. Base UI는 정말 멋진 스타일링 옵션을 하나 더 제공합니다.
00:06:27현재 저는 테일윈드를 쓰고 있는데요, 일반 CSS나 CSS 모듈 등 기존 방식도 당연히 지원합니다.
00:06:33보통 테일윈드에서 이런 컴포넌트를 스타일링할 때는 데이터 속성(data attributes)을 사용합니다.
00:06:38예를 들어 “data-checked”일 때 배경색을 적용하는 식이죠.
00:06:41하지만 스타일이 복잡해지면 테일윈드 클래스 문자열이 너무 길어져 관리가 힘들어질 수 있습니다.
00:06:45이때 Base UI가 제공하는 대안은 클래스 네임에 함수를 사용하는 것입니다.
00:06:50이를 통해 컴포넌트의 상태값에 직접 접근할 수 있습니다. 여기 체크박스 예시에서는
00:06:55체크 여부나 비활성화 여부에 따라 스타일을 적용하고 있습니다. 보시다시피 간단한 조건문을 썼죠.
00:06:59개인적으로는 긴 한 줄짜리 코드에서 데이터 속성을 찾는 것보다,
00:07:04이렇게 작성하는 것이 스타일의 출처를 한눈에 파악하기에 더 낫다고 봅니다.
00:07:08특히 Vanilla CSS를 사용하시는 분들에게는 더 큰 도움이 될 겁니다.
00:07:13또한 제가 좋아하는 “Tailwind Variants” 같은 라이브러리와도 찰떡궁합입니다.
00:07:17상태값을 체크박스 함수에 넘겨주기만 하면, 상단의 Tailwind Variant 설정에서
00:07:22기본 스타일과 변형(variants) 스타일을 따로 관리할 수 있습니다.
00:07:26체크 상태일 때나 비활성화 상태일 때 적용할 스타일을 명확히 구분할 수 있죠.
00:07:31데이터 속성을 쓰는 것보다 훨씬 깔끔하지 않나요? 물론 취향의 차이겠지만,
00:07:35Base UI가 이런 다양한 선택지를 제공한다는 점이 정말 좋습니다.
00:07:40사실 클래스 네임에 함수를 쓰는 방식은 제가 React Aria를 처음 썼을 때 반했던 기능이기도 합니다.
00:07:45학습 곡선은 높지만 강력한 React Aria와, 단순함이 강점인 Radix의 장점을
00:07:49Base UI가 딱 절묘하게 섞어놓은 느낌입니다. 그야말로 궁극의 헤드리스 라이브러리라 할 만하죠.
00:07:53영상에서 다룬 차이점 외에도 장점은 많습니다. Base UI는
00:07:58React Hook Form이나 TanStack Form을 완벽하게 지원하고, 애니메이션 구현도 매우 쉽습니다.
00:08:02인풋 스크러빙(input scrubbing), 중첩 다이얼로그, 호버 시 메뉴 트리거 같은 기능도 포함되어 있죠.
00:08:06활발히 관리되는 프로젝트인 만큼, 합리적인 요청이라면 GitHub에서 적극적으로 응답해 줄 것입니다.
00:08:11그렇다고 해서 지금 당장 Radix로 만든 앱을 Base UI로 다 갈아엎으라는 뜻은 아닙니다.
00:08:14Radix가 완전히 고장 난 건 아니니까요. 하지만 새로 프로젝트를 시작한다면 저는 무조건 Base UI를 쓸 것이고,
00:08:19콤보 박스 같은 특정 기능이 꼭 필요하다면 마이그레이션을 진지하게 고려해 볼 것 같습니다.
00:08:23Base UI에 대한 여러분의 생각은 어떠신가요? 댓글로 알려주시고, 구독도 잊지 마세요. 그럼 다음 영상에서 뵙겠습니다!
00:08:28the key differences that i wanted to go over in this video but there is still loads more like base ui has
00:08:33great support for react hook form and tan stack form it has animation support to make it a nice
00:08:38and easy process to actually animate your components and it even has features like input scrubbing
00:08:42nested dialogues and triggering menus on hover and i'm sure if you have a reasonable request they'd
00:08:47actually respond to it over on the github as it is actively maintained it is also worth saying though
00:08:52that i probably wouldn't jump to migrating my radix app over to base ui straight away as i don't think
00:08:57radix is completely broken if i'm starting a new project i definitely use base ui now and if i wanted
00:09:02a feature like a combo box or an autocomplete i'd also consider migrating my application let me know
00:09:07what you think of base ui in the comments though while you're down there subscribe and as always
00:09:11see you in the next one