@@ -1599,22 +1599,62 @@ When you don't know what to choose, prefer runtime checking and throwing over ty
1599
1599
1600
1600
#### forwardRef/createRef
1601
1601
1602
- Check the [ Hooks section] ( https://github.com/typescript-cheatsheets/react/blob/main/README.md# hooks) for ` useRef ` .
1602
+ For ` useRef ` , check the [ Hooks section] ( /docs/basic/getting-started/ hooks#useref ) .
1603
1603
1604
- ` createRef ` :
1604
+ #### Ref as a Prop (Recommended for React 19+)
1605
+
1606
+ In React 19+, you can access ` ref ` directly as a prop in function components - no ` forwardRef ` wrapper needed.
1607
+
1608
+ ##### Option 1: Inherit all props from a native element
1609
+
1610
+ Use ` ComponentPropsWithRef ` to inherit all props from a native element.
1605
1611
1606
1612
``` tsx
1607
- import { createRef , PureComponent } from " react" ;
1613
+ import { ComponentPropsWithRef , useRef } from " react" ;
1608
1614
1609
- class CssThemeProvider extends PureComponent <Props > {
1610
- private rootRef = createRef <HTMLDivElement >(); // like this
1611
- render() {
1612
- return <div ref = { this .rootRef } >{ this .props .children } </div >;
1613
- }
1615
+ function MyInput(props : ComponentPropsWithRef <" input" >) {
1616
+ return <input { ... props } />;
1617
+ }
1618
+
1619
+ // Usage in parent component
1620
+ function Parent() {
1621
+ const inputRef = useRef <HTMLInputElement >(null );
1622
+
1623
+ return <MyInput ref = { inputRef } placeholder = " Type here..." />;
1614
1624
}
1615
1625
```
1616
1626
1617
- ` forwardRef ` :
1627
+ ##### Option 2: Explicit typing
1628
+
1629
+ If you have custom props and want fine-grained control, you can explicitly type the ref:
1630
+
1631
+ ``` tsx
1632
+ import { Ref , useRef } from " react" ;
1633
+
1634
+ interface MyInputProps {
1635
+ placeholder: string ;
1636
+ ref: Ref <HTMLInputElement >;
1637
+ }
1638
+
1639
+ function MyInput(props : MyInputProps ) {
1640
+ return <input { ... props } />;
1641
+ }
1642
+
1643
+ // Usage in parent component
1644
+ function Parent() {
1645
+ const inputRef = useRef <HTMLInputElement >(null );
1646
+
1647
+ return <MyInput ref = { inputRef } placeholder = " Type here..." />;
1648
+ }
1649
+ ```
1650
+
1651
+ ** Read more** : [ Wrapping/Mirroring a HTML Element] ( /docs/advanced/patterns_by_usecase#wrappingmirroring-a-html-element )
1652
+
1653
+ #### Legacy Approaches (Pre-React 19)
1654
+
1655
+ ##### forwardRef
1656
+
1657
+ For React 18 and earlier, use ` forwardRef ` :
1618
1658
1619
1659
``` tsx
1620
1660
import { forwardRef , ReactNode } from " react" ;
@@ -1648,7 +1688,7 @@ interface Props {
1648
1688
export const FancyButton = forwardRef (
1649
1689
(
1650
1690
props : Props ,
1651
- ref : Ref < HTMLButtonElement > // <-- here!
1691
+ ref : Ref < HTMLButtonElement > // <-- explicit immutable ref type
1652
1692
) => (
1653
1693
<button ref = { ref } className = " MyClassName" type = { props .type } >
1654
1694
{ props .children }
@@ -1659,42 +1699,47 @@ export const FancyButton = forwardRef(
1659
1699
1660
1700
</details >
1661
1701
1662
- If you are grabbing the props of a component that forwards refs, use [ ` ComponentPropsWithRef ` ] ( https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a05cc538a42243c632f054e42eab483ebf1560ab/types/react/index.d.ts#L770 ) .
1702
+ If you need to grab props from a component that forwards refs, use [ ` ComponentPropsWithRef ` ] ( https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a05cc538a42243c632f054e42eab483ebf1560ab/types/react/index.d.ts#L770 ) .
1663
1703
1664
- ` ref ` as a prop:
1704
+ ##### createRef
1665
1705
1666
- React 19, you can access ref as prop for function components .
1706
+ ` createRef ` is mostly used for class components. Function components typically rely on ` useRef ` instead .
1667
1707
1668
1708
``` tsx
1669
- function MyInput({ placeholder , ref }) {
1670
- return <input placeholder = { placeholder } ref = { ref } />;
1671
- }
1709
+ import { createRef , PureComponent } from " react" ;
1672
1710
1673
- // In parent
1674
- <MyInput ref = { ref } />;
1711
+ class CssThemeProvider extends PureComponent <Props > {
1712
+ private rootRef = createRef <HTMLDivElement >();
1713
+
1714
+ render() {
1715
+ return <div ref = { this .rootRef } >{ this .props .children } </div >;
1716
+ }
1717
+ }
1675
1718
```
1676
1719
1677
- Read more [ ` ref ` as a prop ] ( https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop ) .
1720
+ #### Generic Components with Refs
1678
1721
1679
- #### Generic forwardRefs
1722
+ Generic components typically require manual ref handling since their generic nature prevents automatic type inference. Here are the main approaches:
1680
1723
1681
- Read more context in https://fettblog.eu/typescript-react-generic-forward-refs/ :
1724
+ Read more context in [ this article ] ( https://fettblog.eu/typescript-react-generic-forward-refs/ ) .
1682
1725
1683
- ##### Option 1 - Wrapper component
1726
+ ##### Option 1: Wrapper Component
1684
1727
1685
- ``` ts
1686
- type ClickableListProps <T > = {
1728
+ The most straightforward approach is to manually handle refs through props:
1729
+
1730
+ ``` tsx
1731
+ interface ClickableListProps <T > {
1687
1732
items: T [];
1688
1733
onSelect: (item : T ) => void ;
1689
1734
mRef? : React .Ref <HTMLUListElement > | null ;
1690
- };
1735
+ }
1691
1736
1692
1737
export function ClickableList<T >(props : ClickableListProps <T >) {
1693
1738
return (
1694
1739
<ul ref = { props .mRef } >
1695
1740
{ props .items .map ((item , i ) => (
1696
1741
<li key = { i } >
1697
- < button onClick = {(el ) => props.onSelect(item)}> Select < / button >
1742
+ <button onClick = { () => props .onSelect (item )} >Select</button >
1698
1743
{ item }
1699
1744
</li >
1700
1745
))}
@@ -1703,17 +1748,19 @@ export function ClickableList<T>(props: ClickableListProps<T>) {
1703
1748
}
1704
1749
```
1705
1750
1706
- ##### Option 2 - Redeclare forwardRef
1751
+ ##### Option 2: Redeclare forwardRef
1707
1752
1708
- ``` ts
1709
- // Redeclare forwardRef
1753
+ For true ` forwardRef ` behavior with generics, extend the module declaration:
1754
+
1755
+ ``` tsx
1756
+ // Redeclare forwardRef to support generics
1710
1757
declare module " react" {
1711
1758
function forwardRef<T , P = {}>(
1712
1759
render : (props : P , ref : React .Ref <T >) => React .ReactElement | null
1713
1760
): (props : P & React .RefAttributes <T >) => React .ReactElement | null ;
1714
1761
}
1715
1762
1716
- // Just write your components like you're used to!
1763
+ // Now you can use forwardRef with generics normally
1717
1764
import { forwardRef , ForwardedRef } from " react" ;
1718
1765
1719
1766
interface ClickableListProps <T > {
@@ -1729,7 +1776,7 @@ function ClickableListInner<T>(
1729
1776
<ul ref = { ref } >
1730
1777
{ props .items .map ((item , i ) => (
1731
1778
<li key = { i } >
1732
- < button onClick = {(el ) => props.onSelect(item)}> Select < / button >
1779
+ <button onClick = { () => props .onSelect (item )} >Select</button >
1733
1780
{ item }
1734
1781
</li >
1735
1782
))}
@@ -1740,10 +1787,12 @@ function ClickableListInner<T>(
1740
1787
export const ClickableList = forwardRef (ClickableListInner );
1741
1788
```
1742
1789
1743
- ##### Option 3 - Call signature
1790
+ ##### Option 3: Call Signature
1744
1791
1745
- ``` ts
1746
- // Add to `index.d.ts`
1792
+ If you need both generic support and proper forwardRef behavior with full type inference, you can use the call signature:
1793
+
1794
+ ``` tsx
1795
+ // Add to your type definitions (e.g. in `index.d.ts` file)
1747
1796
interface ForwardRefWithGenerics extends React .FC <WithForwardRefProps <Option >> {
1748
1797
<T extends Option >(props : WithForwardRefProps <T >): ReturnType <
1749
1798
React .FC <WithForwardRefProps <T >>
@@ -1754,15 +1803,20 @@ export const ClickableListWithForwardRef: ForwardRefWithGenerics =
1754
1803
forwardRef (ClickableList );
1755
1804
```
1756
1805
1757
- Credits: https://stackoverflow.com/a/73795494
1806
+ Credits: [ https://stackoverflow.com/a/73795494 ] ( https://stackoverflow.com/a/73795494 )
1758
1807
1759
- #### More Info
1808
+ ::: note
1809
+ Option 1 is usually sufficient and clearer. Use Option 2 when you specifically need ` forwardRef ` behavior. Use Option 3 for advanced library scenarios requiring both generics and full forwardRef type inference.
1810
+ :::
1760
1811
1761
- - https://medium.com/@martin_hotell/react-refs-with-typescript-a32d56c4d315
1812
+ #### Additional Resources
1762
1813
1763
- You may also wish to do [ Conditional Rendering with ` forwardRef ` ] ( https://github.com/typescript-cheatsheets/react/issues/167 ) .
1814
+ - [ React refs with TypeScript] ( https://medium.com/@martin_hotell/react-refs-with-typescript-a32d56c4d315 )
1815
+ - [ Conditional rendering with forwardRef] ( https://github.com/typescript-cheatsheets/react/issues/167 )
1764
1816
1765
- [ Something to add? File an issue] ( https://github.com/typescript-cheatsheets/react/issues/new ) .
1817
+ ---
1818
+
1819
+ [ Something to add? File an issue] ( https://github.com/typescript-cheatsheets/react/issues/new )
1766
1820
1767
1821
<!-- END-SECTION:forward-create-ref-->
1768
1822
0 commit comments