Skip to content

Commit 47e8158

Browse files
authored
chore(templates): removes all instances of React.forwardRef (#10331)
Fixes #10325. Since React 19, refs can now be passed directly through props without the need for `React.forwardRef`. This greatly simplifies components types and overall syntax.
1 parent 1cade17 commit 47e8158

File tree

16 files changed

+309
-318
lines changed

16 files changed

+309
-318
lines changed

templates/website/src/components/ui/button.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,19 @@ export interface ButtonProps
3434
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
3535
VariantProps<typeof buttonVariants> {
3636
asChild?: boolean
37+
ref?: React.Ref<HTMLButtonElement>
3738
}
3839

39-
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
40-
({ asChild = false, className, size, variant, ...props }, ref) => {
41-
const Comp = asChild ? Slot : 'button'
42-
return (
43-
<Comp className={cn(buttonVariants({ className, size, variant }))} ref={ref} {...props} />
44-
)
45-
},
46-
)
47-
Button.displayName = 'Button'
40+
const Button: React.FC<ButtonProps> = ({
41+
asChild = false,
42+
className,
43+
size,
44+
variant,
45+
ref,
46+
...props
47+
}) => {
48+
const Comp = asChild ? Slot : 'button'
49+
return <Comp className={cn(buttonVariants({ className, size, variant }))} ref={ref} {...props} />
50+
}
4851

4952
export { Button, buttonVariants }
Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,48 @@
11
import { cn } from 'src/utilities/cn'
22
import * as React from 'react'
33

4-
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
5-
({ className, ...props }, ref) => (
6-
<div
7-
className={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)}
8-
ref={ref}
9-
{...props}
10-
/>
11-
),
4+
const Card: React.FC<
5+
{ ref?: React.Ref<HTMLDivElement> } & React.HTMLAttributes<HTMLDivElement>
6+
> = ({ className, ref, ...props }) => (
7+
<div
8+
className={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)}
9+
ref={ref}
10+
{...props}
11+
/>
1212
)
13-
Card.displayName = 'Card'
1413

15-
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
16-
({ className, ...props }, ref) => (
17-
<div className={cn('flex flex-col space-y-1.5 p-6', className)} ref={ref} {...props} />
18-
),
14+
const CardHeader: React.FC<
15+
{ ref?: React.Ref<HTMLDivElement> } & React.HTMLAttributes<HTMLDivElement>
16+
> = ({ className, ref, ...props }) => (
17+
<div className={cn('flex flex-col space-y-1.5 p-6', className)} ref={ref} {...props} />
1918
)
20-
CardHeader.displayName = 'CardHeader'
2119

22-
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
23-
({ className, ...props }, ref) => (
24-
<h3
25-
className={cn('text-2xl font-semibold leading-none tracking-tight', className)}
26-
ref={ref}
27-
{...props}
28-
/>
29-
),
20+
const CardTitle: React.FC<
21+
{ ref?: React.Ref<HTMLHeadingElement> } & React.HTMLAttributes<HTMLHeadingElement>
22+
> = ({ className, ref, ...props }) => (
23+
<h3
24+
className={cn('text-2xl font-semibold leading-none tracking-tight', className)}
25+
ref={ref}
26+
{...props}
27+
/>
3028
)
31-
CardTitle.displayName = 'CardTitle'
3229

33-
const CardDescription = React.forwardRef<
34-
HTMLParagraphElement,
35-
React.HTMLAttributes<HTMLParagraphElement>
36-
>(({ className, ...props }, ref) => (
30+
const CardDescription: React.FC<
31+
{ ref?: React.Ref<HTMLParagraphElement> } & React.HTMLAttributes<HTMLParagraphElement>
32+
> = ({ className, ref, ...props }) => (
3733
<p className={cn('text-sm text-muted-foreground', className)} ref={ref} {...props} />
38-
))
39-
CardDescription.displayName = 'CardDescription'
34+
)
4035

41-
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
42-
({ className, ...props }, ref) => (
43-
<div className={cn('p-6 pt-0', className)} ref={ref} {...props} />
44-
),
36+
const CardContent: React.FC<
37+
{ ref?: React.Ref<HTMLDivElement> } & React.HTMLAttributes<HTMLDivElement>
38+
> = ({ className, ref, ...props }) => (
39+
<div className={cn('p-6 pt-0', className)} ref={ref} {...props} />
4540
)
46-
CardContent.displayName = 'CardContent'
4741

48-
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
49-
({ className, ...props }, ref) => (
50-
<div className={cn('flex items-center p-6 pt-0', className)} ref={ref} {...props} />
51-
),
42+
const CardFooter: React.FC<
43+
{ ref?: React.Ref<HTMLDivElement> } & React.HTMLAttributes<HTMLDivElement>
44+
> = ({ className, ref, ...props }) => (
45+
<div className={cn('flex items-center p-6 pt-0', className)} ref={ref} {...props} />
5246
)
53-
CardFooter.displayName = 'CardFooter'
5447

5548
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }

templates/website/src/components/ui/checkbox.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
55
import { Check } from 'lucide-react'
66
import * as React from 'react'
77

8-
const Checkbox = React.forwardRef<
9-
React.ElementRef<typeof CheckboxPrimitive.Root>,
10-
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
11-
>(({ className, ...props }, ref) => (
8+
const Checkbox: React.FC<
9+
{
10+
ref?: React.Ref<HTMLButtonElement>
11+
} & React.ComponentProps<typeof CheckboxPrimitive.Root>
12+
> = ({ className, ref, ...props }) => (
1213
<CheckboxPrimitive.Root
1314
className={cn(
1415
'peer h-4 w-4 shrink-0 rounded border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
@@ -21,7 +22,6 @@ const Checkbox = React.forwardRef<
2122
<Check className="h-4 w-4" />
2223
</CheckboxPrimitive.Indicator>
2324
</CheckboxPrimitive.Root>
24-
))
25-
Checkbox.displayName = CheckboxPrimitive.Root.displayName
25+
)
2626

2727
export { Checkbox }
Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
import { cn } from 'src/utilities/cn'
22
import * as React from 'react'
33

4-
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
5-
6-
const Input = React.forwardRef<HTMLInputElement, InputProps>(
7-
({ type, className, ...props }, ref) => {
8-
return (
9-
<input
10-
className={cn(
11-
'flex h-10 w-full rounded border border-border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
12-
className,
13-
)}
14-
ref={ref}
15-
type={type}
16-
{...props}
17-
/>
18-
)
19-
},
20-
)
21-
Input.displayName = 'Input'
4+
const Input: React.FC<
5+
{
6+
ref?: React.Ref<HTMLInputElement>
7+
} & React.InputHTMLAttributes<HTMLInputElement>
8+
> = ({ type, className, ref, ...props }) => {
9+
return (
10+
<input
11+
className={cn(
12+
'flex h-10 w-full rounded border border-border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
13+
className,
14+
)}
15+
ref={ref}
16+
type={type}
17+
{...props}
18+
/>
19+
)
20+
}
2221

2322
export { Input }

templates/website/src/components/ui/label.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ const labelVariants = cva(
99
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
1010
)
1111

12-
const Label = React.forwardRef<
13-
React.ElementRef<typeof LabelPrimitive.Root>,
14-
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
15-
>(({ className, ...props }, ref) => (
12+
const Label: React.FC<
13+
{ ref?: React.Ref<HTMLLabelElement> } & React.ComponentProps<typeof LabelPrimitive.Root> &
14+
VariantProps<typeof labelVariants>
15+
> = ({ className, ref, ...props }) => (
1616
<LabelPrimitive.Root className={cn(labelVariants(), className)} ref={ref} {...props} />
17-
))
18-
Label.displayName = LabelPrimitive.Root.displayName
17+
)
1918

2019
export { Label }

templates/website/src/components/ui/pagination.tsx

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,16 @@ const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
1313
{...props}
1414
/>
1515
)
16-
Pagination.displayName = 'Pagination'
1716

18-
const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'>>(
19-
({ className, ...props }, ref) => (
20-
<ul className={cn('flex flex-row items-center gap-1', className)} ref={ref} {...props} />
21-
),
17+
const PaginationContent: React.FC<
18+
{ ref?: React.Ref<HTMLUListElement> } & React.HTMLAttributes<HTMLUListElement>
19+
> = ({ className, ref, ...props }) => (
20+
<ul className={cn('flex flex-row items-center gap-1', className)} ref={ref} {...props} />
2221
)
23-
PaginationContent.displayName = 'PaginationContent'
2422

25-
const PaginationItem = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(
26-
({ className, ...props }, ref) => <li className={cn('', className)} ref={ref} {...props} />,
27-
)
28-
PaginationItem.displayName = 'PaginationItem'
23+
const PaginationItem: React.FC<
24+
{ ref?: React.Ref<HTMLLIElement> } & React.HTMLAttributes<HTMLLIElement>
25+
> = ({ className, ref, ...props }) => <li className={cn('', className)} ref={ref} {...props} />
2926

3027
type PaginationLinkProps = {
3128
isActive?: boolean
@@ -45,7 +42,6 @@ const PaginationLink = ({ className, isActive, size = 'icon', ...props }: Pagina
4542
{...props}
4643
/>
4744
)
48-
PaginationLink.displayName = 'PaginationLink'
4945

5046
const PaginationPrevious = ({
5147
className,
@@ -61,7 +57,6 @@ const PaginationPrevious = ({
6157
<span>Previous</span>
6258
</PaginationLink>
6359
)
64-
PaginationPrevious.displayName = 'PaginationPrevious'
6560

6661
const PaginationNext = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => (
6762
<PaginationLink
@@ -74,7 +69,6 @@ const PaginationNext = ({ className, ...props }: React.ComponentProps<typeof Pag
7469
<ChevronRight className="h-4 w-4" />
7570
</PaginationLink>
7671
)
77-
PaginationNext.displayName = 'PaginationNext'
7872

7973
const PaginationEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => (
8074
<span
@@ -86,7 +80,6 @@ const PaginationEllipsis = ({ className, ...props }: React.ComponentProps<'span'
8680
<span className="sr-only">More pages</span>
8781
</span>
8882
)
89-
PaginationEllipsis.displayName = 'PaginationEllipsis'
9083

9184
export {
9285
Pagination,

templates/website/src/components/ui/select.tsx

Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ const SelectGroup = SelectPrimitive.Group
1111

1212
const SelectValue = SelectPrimitive.Value
1313

14-
const SelectTrigger = React.forwardRef<
15-
React.ElementRef<typeof SelectPrimitive.Trigger>,
16-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
17-
>(({ children, className, ...props }, ref) => (
14+
const SelectTrigger: React.FC<
15+
{ ref?: React.Ref<HTMLButtonElement> } & React.ComponentProps<typeof SelectPrimitive.Trigger>
16+
> = ({ children, className, ref, ...props }) => (
1817
<SelectPrimitive.Trigger
1918
className={cn(
2019
'flex h-10 w-full items-center justify-between rounded border border-input bg-background px-3 py-2 text-inherit ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
@@ -28,41 +27,39 @@ const SelectTrigger = React.forwardRef<
2827
<ChevronDown className="h-4 w-4 opacity-50" />
2928
</SelectPrimitive.Icon>
3029
</SelectPrimitive.Trigger>
31-
))
32-
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
30+
)
3331

34-
const SelectScrollUpButton = React.forwardRef<
35-
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
36-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
37-
>(({ className, ...props }, ref) => (
32+
const SelectScrollUpButton: React.FC<
33+
{ ref?: React.Ref<HTMLDivElement> } & React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>
34+
> = ({ className, ref, ...props }) => (
3835
<SelectPrimitive.ScrollUpButton
3936
className={cn('flex cursor-default items-center justify-center py-1', className)}
4037
ref={ref}
4138
{...props}
4239
>
4340
<ChevronUp className="h-4 w-4" />
4441
</SelectPrimitive.ScrollUpButton>
45-
))
46-
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
42+
)
4743

48-
const SelectScrollDownButton = React.forwardRef<
49-
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
50-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
51-
>(({ className, ...props }, ref) => (
44+
const SelectScrollDownButton: React.FC<
45+
{ ref?: React.Ref<HTMLDivElement> } & React.ComponentProps<
46+
typeof SelectPrimitive.ScrollDownButton
47+
>
48+
> = ({ className, ref, ...props }) => (
5249
<SelectPrimitive.ScrollDownButton
5350
className={cn('flex cursor-default items-center justify-center py-1', className)}
5451
ref={ref}
5552
{...props}
5653
>
5754
<ChevronDown className="h-4 w-4" />
5855
</SelectPrimitive.ScrollDownButton>
59-
))
60-
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName
56+
)
6157

62-
const SelectContent = React.forwardRef<
63-
React.ElementRef<typeof SelectPrimitive.Content>,
64-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
65-
>(({ children, className, position = 'popper', ...props }, ref) => (
58+
const SelectContent: React.FC<
59+
{
60+
ref?: React.Ref<HTMLDivElement>
61+
} & React.ComponentProps<typeof SelectPrimitive.Content>
62+
> = ({ children, className, position = 'popper', ref, ...props }) => (
6663
<SelectPrimitive.Portal>
6764
<SelectPrimitive.Content
6865
className={cn(
@@ -88,25 +85,23 @@ const SelectContent = React.forwardRef<
8885
<SelectScrollDownButton />
8986
</SelectPrimitive.Content>
9087
</SelectPrimitive.Portal>
91-
))
92-
SelectContent.displayName = SelectPrimitive.Content.displayName
88+
)
9389

94-
const SelectLabel = React.forwardRef<
95-
React.ElementRef<typeof SelectPrimitive.Label>,
96-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
97-
>(({ className, ...props }, ref) => (
90+
const SelectLabel: React.FC<
91+
{ ref?: React.Ref<HTMLDivElement> } & React.ComponentProps<typeof SelectPrimitive.Label>
92+
> = ({ className, ref, ...props }) => (
9893
<SelectPrimitive.Label
9994
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
10095
ref={ref}
10196
{...props}
10297
/>
103-
))
104-
SelectLabel.displayName = SelectPrimitive.Label.displayName
98+
)
10599

106-
const SelectItem = React.forwardRef<
107-
React.ElementRef<typeof SelectPrimitive.Item>,
108-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
109-
>(({ children, className, ...props }, ref) => (
100+
const SelectItem: React.FC<
101+
{ ref?: React.Ref<HTMLDivElement>; value: string } & React.ComponentProps<
102+
typeof SelectPrimitive.Item
103+
>
104+
> = ({ children, className, ref, ...props }) => (
110105
<SelectPrimitive.Item
111106
className={cn(
112107
'relative flex w-full cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
@@ -123,20 +118,17 @@ const SelectItem = React.forwardRef<
123118

124119
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
125120
</SelectPrimitive.Item>
126-
))
127-
SelectItem.displayName = SelectPrimitive.Item.displayName
121+
)
128122

129-
const SelectSeparator = React.forwardRef<
130-
React.ElementRef<typeof SelectPrimitive.Separator>,
131-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
132-
>(({ className, ...props }, ref) => (
123+
const SelectSeparator: React.FC<
124+
{ ref?: React.Ref<HTMLDivElement> } & React.ComponentProps<typeof SelectPrimitive.Separator>
125+
> = ({ className, ref, ...props }) => (
133126
<SelectPrimitive.Separator
134127
className={cn('-mx-1 my-1 h-px bg-muted', className)}
135128
ref={ref}
136129
{...props}
137130
/>
138-
))
139-
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
131+
)
140132

141133
export {
142134
Select,

0 commit comments

Comments
 (0)