리액트 headless 컴포넌트와 디자인시스템을 위해 UI 라이브러리 사용을 중단한 이유

HongBeen Lee·2023년 7월 28일
8

Front End Developer

목록 보기
5/5

리액트로 사내 UI 라이브러리를 제작중에,

headless UI 라이브러리의 개념과 적용기, 다른 라이브러리들과 headless 라이브러리들 간의 비교 등에 대해 잘 쓰여진 아티클을 찾아 번역해보았습니다.

저는 자체 UI 라이브러리를 만드는 입장에서, headless 컨셉을 이해하는데 매우 큰 도움이 되었습니다.

모두 도움이 되길 바랍니다!


원문: Headless components in React and why I stopped using a UI library for our design system

Headless components in React and why I stopped using a UI library for our design system


이 포스팅에서는 Gloat의 디자인 시스템을 빌딩할때 배운것들과

어떻게 UI라이브러리를 사용하는 것에서 (MUI 같은) headless 컴포넌트를 사용하는 것으로 옮겼는지에 집중해보겠다.

우리의 디자인시스템을 빌딩할 때, 난 이 요구사항을 만족해야했다.

  • 접근성: 컴포넌트들은 접근가능해야한다.
  • 테마: 각 컴포넌트들은 여러 테마를 support해야한다(light, dark같은)
  • 유니크함: 우리 프로덕트의 외관은 유니크해야한다. MUI나 부트스트랩같이 제니릭하기 원하지 않는다. 우린 우리의 디자인팀이 있고 우리 프로덕트가 어떻게 보여져야하는지 결정한다.
  • browser support: 우리는 모든 메이저 브라우저와 IE11에 서포트해야한다.
  • 기능: 우리 Gloat만의 독특한 유즈케이스를 서포트해아한다. 우리는 우리의 컴포넌트 동작방식을 완전히 조작해야한다.
  • 반응성: 모든 스크린 사이즈와 디바이스에 서포트해야한다.
  • 유지보수성: 수정/유지하기 쉽고 원활해야한다.

나의 Material UI & React Bootstrap 여정

처음 Gloat에 참여했을때 우리는 react-bootstrap을 사용했다. 우리는 더 복잡한 컴포넌트에만 사용했고,

그 외에 아토믹 컴포넌트(버튼, 체크박스, 아바타 같은)은 우리가 직접 구현했다.

그러나 리액트를 더 잘하게 되면서, 난 MUI가 훨씬 더 좋고 모던한 컴포넌트 API를 가지고있다고 느꼈고,

그래서 점진적으로 6개월간 노력 후에 우리는 우리의 모든 어플리케이션과 디자인 시스템에서 Bootstrap을 MUI로 교체할 수 있었다.

잘 되고있었다!

난 MUI가 테마를 제공하는 방식, 그들의 커스텀 방식을 좋아했고, 그들이 모든 모던한 리액트 best practices(hooks, dot notation 서브 컴포넌트들과 Context 같은)를 사용하는 방식을 좋아했다.

난 나만의 Material UI를 만들거야

얼마 뒤, 우리의 앱은 커져가기 시작했고 우리는 우리의 독특한 use cases를 서포팅할 더 복잡한 UI 컴포넌트들을 구현해야했다. 난 Autocomplete, Combobox, multi-tag-select, Dropdown, Modals과 같은 컴포넌트들을 이야기하고 있는것이다. 그들 각각은 우리 프로덕트에서 독특한 기능을 가지고 우리의 커스텀 디자인을 갖고있었다.

우리의 Combobox 컴포넌트에서 (기본적으로 multi-select이면서 필터링을 허용하는 input을 갖고있음),

난 특정 디자인 요구사항을 구현해야했고 몇가지 커스텀 기능들을 제공해야했다.

예를들면, 몇가지 아이템들을 고르고있을 때 드롭다운을 연채로 유지해야하고 다른것들을 클릭하면 닫아야했다. 난 MUI를 적절하게 우리의 디자인과 기능 요구사항으로 다룰려고 노력했으나 벽에 마주쳤다.

인터넷에서 같은것을 시도하는 다른것에 대해 읽으면서, 난 나의 문제들이 단지 나만의 것이 아님을 알아차렸다.

난 많은 시간을 나의 MUI 컴포넌트에 대한 필요성을 해킹하는데에 보냈고, 그러는 와중에 난 더럽고 복잡하다고 느꼈다. 결국, 난 내가 작성한 코드에 만족하지 못했고, 내 코드가 미래에 유지보수하고 확장하기에 어려울 것이라는 결론에 도달했다.

난 몇가지 고심끝에, 스스로 이런 컴포넌트들을 만들기로 결심했다.

난 기능과 디자인에 대한 완전한 컨트롤과 깨끗하고 변화에 열려있는 코드를 원했다. 이것이 큰 실수였다.

그 결과는 결국 길어지고, 복잡하고 이해하기 어려운 나의 코드가 남았다. 그러나 그게 유일한 문제가 아니었다.

난 IE와 사파리 사용자들, 몇가지 모바일 디바이스로부터 버그들을 얻기 시작했다. 그것들은 적절히 테스트되지 않았었다.

“Can’t select a dropdown item on some iOS devices on Safari (BUG-34939)” 따위의 버그들에 대해서 이야기하고 있는 것이다.

전반적으로 가장 큰 문제는 접근성이었다. 나의 수제 컴포넌트들은 간단하게 키보드 유저들과 스크린 리더 사용자들에 대해 충분히 접근가능하지 않았다. 내가 이것들을 스스로 만듦으로서 가진 유일한 베네핏은 기능, markup, 디자인에 대한 완전한 컨트롤뿐이었다.

난 포기했고 스스로에게 말했다. “well, stupid me, MUI로 돌아가자. 사람들이 쓰는데에는 이유가 있을거야”.

"A slide from  Pedro Duarte ’s talk at Next.js conf in 2021. Pedro is one of the creators of Radix UI, and here he describes how much time it took them to implement a fully accessible dropdown menu that works well in all browsers and supports all screen readers."

Headless components - 그들은 어떻게 도움을 주는가?

그러나 곧 난 Israeli React Facebook group에서 한 질문을 보았다.

“React에서 최고의 UI 라이브러리는 무엇인가?”

솔직하게, 이 질문은 매 달마다 올라오는 질문이고 그것은 우리 프론트엔드 개발자들에게 많은 감정을 불러일으킨다. 난 나의 주의를 사로잡는 댓글을 볼때까지 다른 의견들을 읽었다.

그룹 멤버(called Nick Ribal) 는 그는 절대 UI 라이브러리들을 사용하지 않고 항상 그만의 컴포넌트를 손수 만든다는 멘션을 남겼다. 난 이 사람이 FB그룹 소속인걸 알았고, 그는 그가 뭘 말하고 있는지 안다는 것을 기억해서 질문했다.

“당신은 어떻게 모든 까다로운 컴포넌트들(autocomplete, combobox, multi-select and menu dropdowns 같은)을 처리합니까?
이것들은 매우 복잡하고, 키보드 조작과 특정 마크업이 필요하고, 모든곳에서 잘 동작해야하는데요”.

난 직접 구현했던 컴포넌트의 나쁜 경험 때문에 질문했었다. 지금 나는 모든 브라우저에서 잘 작동하고, 접근 가능한 좋은 autocomplete를 만드는 것이 몇달이 걸릴 수 있다는걸 안다. 난 시도했었고 실패했다.

Nick은 그 문제를 해결하기 위해서 “headless components”를 사용한다고 말했고 나에게 Reach UI 라이브러리 문서를 확인해보라고 했다.

난 그들의 웹에 들어가서 Reach UI가 제공하는 컴포넌트들은 접근성과 기능을 책임지지만, 모든 디자인은 당신이 스스로 핸들링하라고 남겨놓았다는것을 배웠다.

난 이 컨셉이 흥미롭다고 생각했지만 충분히 깊이 인상적이지 않았다.

여전히 “어떻게 그것들이 날 도울 수 있을지 혹은 모두가 사용하고 엄중하게 테스트되고있는 MUI보다 더 나을 수 있을지 잘 모르겠어.” 라고 생각했다.

Side note: I think that the very old-fashioned design of the Reach UI website made me go away and not take this library seriously. A month ago, when I interviewed Kent C. Dodds on my podcast, He told me that the authors of Reach UI, which are also the authors of Remix (and react-router), actually came up with the idea for Remix when they started rewriting the entire Reach UI website. I’m happy that they’ve understood that their doc site needs some improvements :)

Headless components - 완전히 새로운 세계

그 시점에서, 난 트위터를 사용하기 시작했다. 난 트위터를 하는 것이 나를 어떻게 더 나은 개발자로 만들어주는지에 대해서는 자세히 말하지 않겠지만,

내가 나의 피드를 스크롤링했을 때 난 이 새롭고 흥분되는 라이브러리 “Headless UI”(리액트를 위한 접근 가능하고 스타일없는 컴포넌트를 제공해주는 UI 라이브러리) 라는 것에 대해 읽기 시작했다.

그래서 우리는 이 컴포넌트들에 원하는 스타일링을 할 수 있다.

난 그들의 웹사이트에 들어갔고 그들의 접근에 대해 배우기 시작했다. 그 후에, 그들의 Github 레포지토리에 들어갔고 그들의 코드를 읽기 시작했고, 그것을 매우 맘에 들었다!

그래서 난 우리의 menu-dropdown 컴포넌트를 Headless UI를 사용하여 리팩터하기로 결심했다.

몇시간 후에 나의 스타일을 가진 접근 가능한 메뉴 컴포넌트를 만들 수 있었고 실제로 우리의 프로덕트와 디자인 시스템에서 모든 그것의 인스턴스들이 교체되었다.


전혀 스타일링되지 않은 headless ui를 가지고 만든 첫번째 버전의 메뉴. 그러나 우리는 열고 닫는 기능과 박스 바깥에 포커스 관리를 얻을 수 있다.


headless ui의 메뉴의 DOM output 스냅샷. 우리는 마크업이 유효하고, 접근가능한 속성들( role, tabIndex, aria-haspopup  같은)을 포함하고 있음을 확인할 수 있다.


약간의 CSS를 추가한 우리의 최종버전 메뉴.

Headless UI의 컴포넌트들은 다양한 브라우저와 플랫폼, 디바이스에 대해서 잘 테스트되었고,
내가 절대 할수없거나 내 스스로 핸들링하기 원하지 않는 엣지 케이스들에 대해 잘 핸들링하고 있다. (예를 들어, 포커스 관리, 키보드 네비게이션, 이벤트 리스너, 접근가능 속성, 유효한 마크업, 스크린 리더 서포트와 같은..)

난 마침에 Nick이 뭘 말한것인지 이해한것같았다.

그래서 난 리액트의 headless 컴포넌트들에 대해 읽기 시작했고 마침에 그들을 이해했다.

컨셉은 아주 기본적이다. 이 라이브러리들은 너에게 잘 테스트되고 접근 가능한 컴포넌트들이나 hooks를 기본 스타일링 없이 제공해줄 것이다. 그래서 넌 원하는대로 스타일링하고 렌더할 수 있다. 그리고 만약 저자가 충분히 친절하다면 넌 또한 그들의 기능과 행동까지 컨트롤할 수 있을 것이다.

headless 컴포넌트들을 조사하면서, 난 여러 유명한 라이브러리들을 발견했다.

  • Radix UI: 나의 최애. 잘 테스트되었고 접근가능하면서, 내가 본 중에 최고의 컴포넌트 API 중 하나이다. React Testing Library를 가지고 테스트할 때 몇 가지 문제들을 갖고있다. 그리고 IE를 매우 잘 서포트하지 않는다.
  • Reach UI: 매우 좋고 신뢰할 수 있다. react-router와 Remix의 저자들로 부터 만들어짐. 많은 컴포넌트들이 있지 않지만 대부분의 유즈케이스들을 커버한다.
  • Headless UI: 작은 수의 컴포넌트들. 잘 테스트되었고 Tailwind CSS와 가장 잘 동작한다. 유일한 약점은 컴포넌트들의 기능과 동작을 변경하는게 쉽지 않다.
  • Downshift: By Kent C. Dodds. autocomplete, select, combobox, and multi combobox 컴포넌트들에 집중한다. 잘 테스트되었고 접근가능하며 스타일과 기능을 완벽하게 제어할 수 있다. 난 우리의 combobox와 autocomplete 컴포넌트에 적용했고, 그들의 구현으로 부터 많이 배웠다.
  • React-aria: By Adobe. 난 이것에 대해 잘 알지 않지만 흥미로워 보인다.
  • Reakit
  • Ariakit

이것들을 큰 라이브러리들인 반면, 많은 단일 컴포넌트 패키지들이 있다. 이것들은 오직 한가지 컴포넌트 타입에 집중한다. headless modal, headless pagination, headless radio buttn 등.

나의 최애 중 하나는 react-table by Tanner Linsley, which is a headless… table.

The Combobox example

이것은 우리의 Downshift를 사용해서 작성된 콤보박스 컴포넌트의 예시이다.

우리의 콤보박스는 몇가지 독특한 기능들과 디자인을 가진다.

이 디자인과 우리가 필요한 기능을 MUI로 구현하는 것은 가능하지만, 훨씬 더 복잡하고 뒤얽힌다.

저는 MUI에 반항하는 동시에 headless 컴포넌트들이 정확히 이것을 위해 설계되었다.

Downshift를 사용함으로서, 난 접근가능한 콤보박스를 만들었다. 이것은 모든 스크린 리더 유저들에 대해 잘 테스트되었고 키보드 navigation을 가지고 있고, 이 유형의 컴포넌트가 필요한 대부분의 로직을 지니고 있다.

그리고 이 모든것은 한두시간안에 이루어졌다.

게다가 우리가 렌더링 로직을 컨트롤하기 때문에, 우리는 사실 우리가 원하는 마크업을 렌더할 수 있고, 어떤 다른 마크업이나 기능을 우리 스스로 추가할 수 있다.

난 긴 리스트의 가상화를 위해서 이것을 react-virtual 라이브러리와 결합시켰다.

이 경우에 headless 컴포넌트들은 나에게 최고의 두가지 세상을 선사했다.

  1. 그들은 접근가능하고 믿을만하다 MUI의 컴포넌트만큼
  2. 그러나 난 스타일링과 기능을 완전히 통제한다.


콤보박스 컴포넌트의 naive한 예시. headless 컴포넌트는 단지 우리가 우리의 마크업에 전달할 수 있는 prop getter들을 반환하는 useCombobox hook이다. 이 props는 타이핑되는 동안의 input에서 발생하는 모든 포커스 관리와 인터렉션을 담당하는 getInputProps 메서드에서부터 반환된다. 그러니까 우리는 이 복잡한 기능들을 우리 스스로 구현할 필요가 없을 것이다. 이 hook이 스타일링을 담당하지 않기 때문에, 우리는 이 컴포넌트를 우리가 원하는대로 스타일링할 수 있다.

번들 사이즈

headless 컴포넌트를 사용하는 다른 이득은 그들을 나의 최종 번들을 부풀리지 않는다는 것이다.

내가 오직 내가 필요한 컴포넌트들과 hooks를 import하기 때문에, 난 최종 번들이 메이저 UI 라이브러리를 설치할 때 항상 딸려오는 다른 어떤 코드들없이 최소로 구성될 것을 알 수 있다.

스타일링

스타일링에 대해, headless 컴포넌트들은 어떤 스타일링 해결책과도 잘 동작할 것이다.

만약 당신이 Tailwind CSS를 사용한다면, 단지 그들의 class를 마크업에 사용해라.

만약 CSS-in-JS가 당신의 기술스택이라면, 당신은 쉽게 컴포넌트들을 스타일할 수 있다.

당신은 대게 복잡하고 가끔은 그 라이브러리의 특정 구현에 의존적인 “UI 라이브러리의 customization 매커니즘” 을 사용할 필요가 없다.

Headless 컴포넌트 라이브러리 사용의 단점

  • 더 제어할 수 있지만 또한 더 책임감이 있다. - Headless 컴포넌트들은 우리에게 더 제어 기능을 주는 반면 그 과정에서 우리는 더 많은 결정이 필요하다는 tradeoff가 존재한다. Headless 컴포넌트들이 보통 접근성과 기능에만 책임을 지기 때문에, 우리는 여전히 스타일링과 대부분의 렌더링 로직을 우리 스스로 구현해야 한다 우리는 심지어 이것들을 사용할 때 더 많은 UX에 관한 결정을 내려야 할 것이다. 그들은 그것에 대해 그다지 의견이 없기 때문이다.
  • 커뮤니티 - UI 라이브러리들(MUI, Bootstrap, Ant Design 같은)은 큰 커뮤니티를 가지고 있다. 우리는 항상 우리의 문제들에 대한 솔루션을 그들의 Github 이슈 페이지에서 찾거나, 버그 수정사항들이 정기적으로 게시된다. Headless 라이브러리들 또한 강력한 커뮤니티가 뒤에 있긴 하지만, 그들은 메이저 UI 라이브러리들의 커뮤니티에 비해 크거나 활동적이지 않다.

언제 headless 컴포넌트보다 UI 라이브러리를 선호할까?

이 포스트를 작성할 때, 난 headless 컴포넌트들을 사용할 몇가지 단점을 찾기 원했다.

그리고 나의 첫 생각은 만약 당신이 매우 빠르게 프로덕트를 제공해야한다면, UI 라이브러리를 사용하는 것보다 headless 컴포넌트들을 사용하는 것이 방해가 될 수 있을 것이었다.

결국, UI 라이브러리의 autocomplete를 렌더링하는 것이 간단하고 더 직관적이고 우리는 단지 <Autocomplete /> 를 런더하고 몇가지 props를 넘겨주기만 하면 된다.

그러나 headless 컴포넌트에 대한 나의 경험으로 볼 때, 같은 컴포넌트를 headless 라이브러리를 사용하여 구현하는 것은 더 긴 시간이 들지 않았고 우리에게 장기적으로 훨씬 더 많은 것을 제공한다.

그래서 나의 현재 대답은 만약 당신이 난 유니크한 기능들과 커스텀 디자인을 가진 디자인 시스템을 빌딩하고 있다는 것을 안다면 난 완전히 headless 컴포넌트들을 사용할 것이다. 난 만약 내가 커스터마이징하는데에 많은 노력을 들이지 않고 대부분의 요구사항을 풀 수 있다고 느낀다면 아마 UI 라이브러리를 고를 수도 있다.

나의 특정 유즈케이스에서 난 우리 프로덕트의 매우 유니크한 여러 기능과 디자인을 제공해야 했다. 그리고 이것들을 UI 라이브러리로 구현하는 것은 가치있지 않았다.

결론

headless 컴포넌트들을 발견하고 포용하는 동안, 난 내가 매우 독특한 설계 요구사항들을 가진 프로젝트에서 UI 라이브러리들을 사용하기 필요치않고 원치 않는다는 걸 느꼈다. Headless 컴포넌트를 사용하는 것은 개발자 경험, 유저 경험, 그리고 우리의 디자인 팀과의 관계에 놀라운 일을 해냈다.

우리가 얻은 다른 이득은 그것이 우리가 보편적으로 리액트 컴포넌트들을 작성하는 방식을 향상시켰다는 것이다. 로직과 기능을 UI로 부터 분리한다.

나의 추천은 headless 컴포넌트의 컨셉이 친숙해지는 것과 당신의 프로젝트 유즈 케이스에 들어맞는지 확인해보라는 것이다.

나의 headless 컴포넌트에 관한 이야기를 시청해라.

from the ReactNext conf June, 2022: https://www.youtube.com/watch?v=BVLBNqW4ves

Also, feel free to follow me on Twitter. @nirbenya

 [Nir Ben-Yair (@nirbenya) / 트위터

Frontend Team Lead @Gloat_com, Chelsea fan, Creator of https://t.co/yfCezgogZS & co host of @FrontendLandIO

twitter.com](https://twitter.com/nirbenya)


👍🏻..

profile
🏃🏻‍♀️💨

3개의 댓글

comment-user-thumbnail
2023년 7월 28일

잘 봤습니다. 좋은 글 감사합니다.

답글 달기
comment-user-thumbnail
2023년 10월 6일

좋은 글 감사합니다. ^^

답글 달기
comment-user-thumbnail
2024년 2월 3일

감사합니다 덕분에 headless컴포넌트에 대하여 자세히 알게되었습니다!

답글 달기