Radix는 끝났습니다, 대신 이걸 쓰세요... (Base UI)

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

Transcript

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

Key Takeaway

유지보수가 정체된 Radix UI 대신, 더 명시적인 API와 강력한 기능을 제공하며 활발히 개발 중인 Base UI로의 전환이 권장됩니다.

Highlights

Radix UI의 원년 멤버들이 모여 만든 새로운 헤드리스 라이브러리인 Base UI 소개

Radix UI의 유지보수 중단 문제와 Base UI의 활발한 개발 및 커뮤니티 지원 차이점

asChild 속성 대신 더욱 명시적인 render 프롭 방식을 도입하여 개발자 경험 개선

상태 기반 스타일링을 지원하여 Tailwind 및 Vanilla CSS와 유연한 결합 가능

Radix에는 없었던 콤보 박스

Timeline

Base UI 소개 및 탄생 배경

Radix UI와 Material UI를 제작했던 핵심 개발자들이 모여 만든 새로운 헤드리스 UI 라이브러리인 Base UI를 소개합니다. 헤드리스 UI는 기능과 접근성은 라이브러리가 담당하고 디자인은 개발자가 직접 정의하는 방식으로, AI 시대에 더욱 중요해진 정교한 접근성 처리를 지원합니다. Base UI는 Radix에는 없는 콤보 박스 같은 고급 컴포넌트를 포함하여 개발자들에게 더 넓은 선택지를 제공합니다. 공식 문서는 CSS 모듈과 테일윈드 예시를 모두 제공하여 구현의 편의성을 극대화했습니다. 이 섹션은 왜 기존 Radix 사용자들이 Base UI에 주목해야 하는지 기초적인 배경을 설명합니다.

Radix UI의 위기와 유지보수 현황 비교

Radix UI가 현재 활발한 업데이트가 없는 이른바 "좀비 상태"에 빠졌다는 점을 GitHub 통계와 함께 지적합니다. Radix는 기업 인수 이후 투자가 거의 이루어지지 않아 한 달간 처리된 PR이나 이슈가 전무한 반면, Base UI는 수백 개의 작업을 처리하며 활발히 성장 중입니다. 심지어 Radix의 공동 제작자조차 현재는 Base UI 팀에서 일하며 프로젝트의 미래를 Base UI에 두고 있다고 언급했습니다. 개발자들은 미래의 버그 수정과 지속 가능성을 위해 활발히 관리되는 의존성을 선택해야 합니다. 프로젝트의 장기적인 안정성을 고려할 때 라이브러리의 관리 상태가 얼마나 중요한지 강조하는 구간입니다.

asChild를 대체하는 더 명시적인 render 프롭

Radix의 asChild 프롭이 가진 불명확함을 해결하기 위해 Base UI가 도입한 render 프롭 방식을 상세히 설명합니다. asChild는 자식 요소와 속성을 병합할 때 코드를 읽는 개발자가 의도를 놓치기 쉽다는 단점이 있었습니다. 반면 Base UI의 render 프롭은 렌더링할 요소를 직접 명시하므로 훨씬 직관적이고 가독성이 높습니다. 또한 render 프롭에 함수를 전달하여 컴포넌트 내부의 체크 여부나 비활성화 상태 같은 데이터에 직접 접근할 수 있는 유연함을 제공합니다. 이러한 변화는 단순한 스타일 수정을 넘어 복잡한 인터랙션을 구현할 때 개발자에게 더 강력한 제어권을 부여합니다.

데이터 기반 렌더링과 멀티 셀렉트 기능

Base UI가 데이터를 처리하는 방식과 Radix에서 가장 요청이 많았던 멀티 셀렉트 기능의 지원 여부를 다룹니다. Base UI는 부모 컴포넌트에 직접 데이터 배열을 전달하는 데이터 기반 방식을 사용하여 SSR 환경에서의 성능 최적화를 꾀합니다. 기존 Radix에서는 구현하기 까다로웠던 멀티 셀렉트 기능을 multiple 프롭 하나로 간단히 활성화할 수 있다는 점이 큰 강점입니다. 스피커는 데이터 배열을 두 번 작성해야 하는 현재의 방식에 대해 React Aria와 같은 개선 아이디어를 제안하기도 합니다. 이는 복잡한 폼 요소를 다루는 개발자들에게 실질적인 생산성 향상을 약속하는 핵심 기능들입니다.

유연한 스타일링 옵션과 라이브러리의 미래

클래스 네임에 함수를 사용하여 컴포넌트 상태에 따른 스타일을 조건부로 적용하는 혁신적인 스타일링 방식을 소개합니다. 이 방식은 Tailwind Variants와 같은 도구와 함께 사용할 때 데이터 속성을 일일이 찾는 것보다 훨씬 깔끔한 코드 구조를 만들어 줍니다. Base UI는 단순한 기능 제공을 넘어 React Hook Form과의 통합, 애니메이션 지원 등 현대적인 웹 개발 요구사항을 충실히 반영하고 있습니다. 스피커는 당장 모든 프로젝트를 마이그레이션할 필요는 없지만, 신규 프로젝트라면 무조건 Base UI를 선택할 것이라고 단언합니다. 마지막으로 활발한 커뮤니티 소통의 중요성을 언급하며 시청자들에게 새로운 변화에 동참할 것을 권유합니다.

Community Posts

View all posts