Skip to content

Commit 616a986

Browse files
authored
chore(radix) - remove react-label (#780)
* remove label && slot * remove react-label dependency * remove dependency * format * adapt plan * remove directives
1 parent 3a2eccb commit 616a986

9 files changed

Lines changed: 281 additions & 90 deletions

File tree

example/package-lock.json

Lines changed: 1 addition & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 0 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@
9191
"@radix-ui/react-checkbox": "^1.3.3",
9292
"@radix-ui/react-collapsible": "^1.1.12",
9393
"@radix-ui/react-dialog": "^1.1.15",
94-
"@radix-ui/react-label": "^2.1.8",
9594
"@radix-ui/react-popover": "^1.1.15",
9695
"@radix-ui/react-radio-group": "^1.3.8",
9796
"@radix-ui/react-scroll-area": "^1.2.10",

plans/headless-library.md

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
# Headless Library Plan
2+
3+
## Goal
4+
5+
Decouple all Radix UI (and other visual) dependencies from the library core, making it fully headless. Consumers bring their own UI components. All current default/example implementations move to an `examples/` folder.
6+
7+
## Current State
8+
9+
### Radix packages in use (11 total)
10+
11+
- `@radix-ui/react-accordion``ui/accordion.tsx`
12+
- `@radix-ui/react-checkbox``ui/checkbox.tsx`
13+
- `@radix-ui/react-collapsible``ui/collapsible.tsx`
14+
- `@radix-ui/react-dialog``ui/dialog.tsx`
15+
- `@radix-ui/react-label``ui/label.tsx`, `ui/form.tsx`
16+
- `@radix-ui/react-popover``ui/popover.tsx`
17+
- `@radix-ui/react-radio-group``ui/radio-group.tsx`
18+
- `@radix-ui/react-scroll-area``ui/scroll-area.tsx`
19+
- `@radix-ui/react-select``ui/select.tsx`
20+
- `@radix-ui/react-slot``ui/form.tsx` (`FormControl`)
21+
- `@radix-ui/react-tabs``ui/tabs.tsx`
22+
23+
### Visual components embedded in flows/shared (must be made overridable or moved)
24+
25+
- `EstimationResults` — uses `Card`, `Accordion`, `BasicTooltip`, `ActionsDropdown`
26+
- `SummaryResults` — uses `Card`, `Accordion`
27+
- `Termination/PaidTimeOff` — uses `Button`
28+
- `ContractorOnboarding/ContractPreviewStatement` — uses `Alert`
29+
- `ActionsDropdown` — uses `Button` from `ui/button`
30+
31+
---
32+
33+
## Phases
34+
35+
### Phase 1 — Simplify `src/components/ui/form.tsx`
36+
37+
Remove the two Radix dependencies while keeping the helper pattern intact.
38+
39+
**Changes:**
40+
41+
- `FormLabel`: replace `@radix-ui/react-label` + `Label` with a plain `<label>` element.
42+
- `FormControl`: replace `@radix-ui/react-slot` `Slot` with a lightweight wrapper that clones the child and merges `id` + `aria-*` props using `React.cloneElement`, keeping accessibility intact.
43+
- Remove imports: `@radix-ui/react-label`, `@radix-ui/react-slot`, `Label`.
44+
45+
`FormField`, `FormItem`, `FormDescription`, `FormMessage` require no changes (no Radix).
46+
47+
---
48+
49+
### Phase 2 — Move all Default components to `examples/`
50+
51+
All files in `src/components/form/fields/default/` are reference implementations that depend on Radix-backed `ui/` components. Move them to `examples/fields/`.
52+
53+
**Files to move:**
54+
55+
```
56+
src/components/form/fields/default/ButtonDefault.tsx
57+
src/components/form/fields/default/CheckboxFieldDefault.tsx
58+
src/components/form/fields/default/CountryFieldDefault.tsx
59+
src/components/form/fields/default/DatePickerFieldDefault.tsx
60+
src/components/form/fields/default/EmailFieldDefault.tsx
61+
src/components/form/fields/default/FieldsetToggleButtonDefault.tsx
62+
src/components/form/fields/default/FileUploadFieldDefault.tsx
63+
src/components/form/fields/default/MultiSelectFieldDefault.tsx
64+
src/components/form/fields/default/NumberFieldDefault.tsx
65+
src/components/form/fields/default/RadioGroupFieldDefault.tsx
66+
src/components/form/fields/default/SelectFieldDefault.tsx
67+
src/components/form/fields/default/StatementDefault.tsx
68+
src/components/form/fields/default/TextAreaFieldDefault.tsx
69+
src/components/form/fields/default/TextFieldDefault.tsx
70+
src/components/form/fields/default/WorkScheduleFieldDefault.tsx
71+
```
72+
73+
Also move shared defaults:
74+
75+
```
76+
src/components/shared/drawer/DrawerDefault.tsx
77+
src/components/shared/zendesk-drawer/ZendeskDrawerDefault.tsx
78+
src/components/shared/pdf-preview/PDFPreviewDefault.tsx
79+
src/components/shared/table/TableFieldDefault.tsx
80+
```
81+
82+
Target structure:
83+
84+
```
85+
examples/
86+
fields/
87+
CheckboxFieldDefault.tsx
88+
TextFieldDefault.tsx
89+
... (all field defaults)
90+
shared/
91+
DrawerDefault.tsx
92+
ZendeskDrawerDefault.tsx
93+
PDFPreviewDefault.tsx
94+
TableFieldDefault.tsx
95+
ui/
96+
accordion.tsx (moved from src/components/ui/)
97+
button.tsx
98+
checkbox.tsx
99+
... (all Radix-backed ui primitives)
100+
```
101+
102+
---
103+
104+
### Phase 3 — Remove `src/components/ui/` Radix components from the library
105+
106+
Move all Radix-backed UI primitives to `examples/ui/`. These become reference implementations consumers can copy or replace.
107+
108+
**Files to move to `examples/ui/`:**
109+
110+
```
111+
src/components/ui/accordion.tsx
112+
src/components/ui/badge.tsx
113+
src/components/ui/basic-tooltip.tsx
114+
src/components/ui/button.tsx
115+
src/components/ui/calendar.tsx
116+
src/components/ui/checkbox.tsx
117+
src/components/ui/collapsible.tsx
118+
src/components/ui/command.tsx
119+
src/components/ui/dialog.tsx
120+
src/components/ui/drawer.tsx
121+
src/components/ui/file-uploader.tsx
122+
src/components/ui/label.tsx
123+
src/components/ui/multi-select.tsx
124+
src/components/ui/popover.tsx
125+
src/components/ui/radio-group.tsx
126+
src/components/ui/scroll-area.tsx
127+
src/components/ui/select.tsx
128+
src/components/ui/tabs.tsx
129+
```
130+
131+
**Files that use only native HTML (no Radix) — can stay or move to examples:**
132+
133+
```
134+
src/components/ui/alert.tsx — pure HTML, no Radix
135+
src/components/ui/card.tsx — pure HTML, no Radix
136+
src/components/ui/input.tsx — pure HTML, no Radix
137+
src/components/ui/table.tsx — pure HTML, no Radix
138+
src/components/ui/textarea.tsx — pure HTML, no Radix
139+
```
140+
141+
These pure-HTML components have no Radix dependency but are still visual. Move them to `examples/ui/` as well so `src/components/ui/` is fully removed from core.
142+
143+
---
144+
145+
### Phase 4 — Make flows with embedded visual components headless
146+
147+
For each flow component that directly renders visual elements (Card, Button, Alert, Accordion), replace the hardcoded component with either:
148+
149+
- **Component override slot** via a `components` prop (preferred for public-facing output components).
150+
- **Native HTML equivalent** where the component is simple enough (e.g., `Button``<button>`, `Card``<div>`).
151+
152+
#### 4a. `EstimationResults`
153+
154+
Currently accepts a partial `components` prop. Extend it to cover all internal visual dependencies:
155+
156+
```ts
157+
type EstimationResultsComponents = {
158+
Accordion?: React.ComponentType<...>;
159+
Tooltip?: React.ComponentType<{ content: React.ReactNode; children: React.ReactNode }>;
160+
ActionsDropdown?: React.ComponentType<ActionsDropdownProps>;
161+
HiringSection?: React.ComponentType<...>; // already exists
162+
OnboardingTimeline?: React.ComponentType<...>; // already exists
163+
Header?: React.ComponentType<...>; // already exists
164+
Footer?: React.ComponentType; // already exists
165+
};
166+
```
167+
168+
The default for each slot is a plain HTML fallback (no Radix).
169+
170+
#### 4b. `SummaryResults`
171+
172+
Same approach — accept `Card` and `Accordion` overrides. Provide plain HTML defaults.
173+
174+
#### 4d. `Termination/PaidTimeOff`
175+
176+
Replace `Button` import with a `components?.button` override or a plain `<button>`.
177+
178+
#### 4f. `ActionsDropdown`
179+
180+
Replace `Button` from `ui/button` with a native `<button>` element directly. `ActionsDropdown` is already a plain dropdown with no Radix — only the `Button` wrapper is Radix-backed.
181+
182+
---
183+
184+
### Phase 5 — Remove all `@radix-ui/*` from `package.json`
185+
186+
After phases 1–4, verify no file in `src/` imports from `@radix-ui/*`. Then remove all 11 Radix entries from `package.json` dependencies.
187+
188+
Run a final audit:
189+
190+
```bash
191+
grep -r "@radix-ui" src/
192+
```
193+
194+
Expected result: zero matches.
195+
196+
---
197+
198+
## File structure after completion
199+
200+
```
201+
src/
202+
components/
203+
form/
204+
fields/ # field controllers (no Radix — use react-hook-form only)
205+
CheckBoxField.tsx
206+
TextField.tsx
207+
...
208+
ui/
209+
form.tsx # simplified — no Radix (FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage)
210+
shared/
211+
actions-dropdown/
212+
ActionsDropdown.tsx # uses native <button>, no Radix
213+
drawer/
214+
Drawer.tsx # headless — delegates to components context
215+
table/
216+
Table.tsx
217+
zendesk-drawer/
218+
ZendeskDrawer.tsx
219+
220+
examples/
221+
ui/
222+
accordion.tsx
223+
button.tsx
224+
card.tsx
225+
checkbox.tsx
226+
...
227+
fields/
228+
CheckboxFieldDefault.tsx
229+
TextFieldDefault.tsx
230+
...
231+
shared/
232+
DrawerDefault.tsx
233+
ZendeskDrawerDefault.tsx
234+
TableFieldDefault.tsx
235+
PDFPreviewDefault.tsx
236+
```
237+
238+
---
239+
240+
## What does NOT change
241+
242+
- react-hook-form is kept — it has no visual opinion and is core to how fields work.
243+
- `FormField` (Controller wrapper) stays in `form.tsx`.
244+
- All hooks, contexts, API client code, and type definitions stay untouched.
245+
- The `components` prop pattern on field controllers stays — consumers still pass their own implementations the same way.
246+
- CSS class names (`RemoteFlows__*`) stay on all components.
247+
248+
---
249+
250+
## Open questions before starting
251+
252+
1. **`form.tsx` `FormControl` replacement**: Use `React.cloneElement` or remove entirely? Since Default components move to examples and those are the only `FormControl` consumers, we could remove `FormControl` from the core export and let examples bring their own version.
253+
254+
2. **`EstimationResults` plain HTML defaults**: When no `Card`/`Accordion` override is given, should the component render plain `<div>` fallbacks (keeping it functional but unstyled), or should it throw (forcing the consumer to provide all slots)? Recommendation: plain `<div>` fallbacks so the component works out-of-the-box without any Radix.
255+
256+
3. **Naming the examples folder**: `examples/` vs `packages/ui/` vs keeping it in the repo as a separate package. TBD with team.

src/components/ui/checkbox.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client';
2-
31
import * as React from 'react';
42
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
53
import { Check } from 'lucide-react';

src/components/ui/dialog.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client';
2-
31
import * as React from 'react';
42
import * as DialogPrimitive from '@radix-ui/react-dialog';
53
import { XIcon } from 'lucide-react';

src/components/ui/drawer.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client';
2-
31
import * as React from 'react';
42
import { Drawer as DrawerPrimitive } from 'vaul';
53

0 commit comments

Comments
 (0)