diff --git a/README.md b/README.md
index 919c8a179..3ca1dba77 100644
--- a/README.md
+++ b/README.md
@@ -134,6 +134,10 @@ React has documentation for [how to start a new React project](https://react.dev
- [Gatsby](https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/): `npm init gatsby --ts`
- [Expo](https://docs.expo.dev/guides/typescript/): `npx create-expo-app -t with-typescript`
+If you just want a client-side single-page app without a framework, [Vite](https://vitejs.dev/) is the most common choice:
+
+- [Vite](https://vitejs.dev/guide/): `npm create vite@latest my-app -- --template react-ts`
+
#### Try React and TypeScript online
There are some tools that let you run React and TypeScript online, which can be helpful for debugging or making sharable reproductions.
@@ -406,11 +410,11 @@ function DelayedEffect(props: { timerMs: number }) {
#### useRef
-In TypeScript, `useRef` returns a reference that is either [read-only](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/abd69803c1b710db58d511f4544ec1b70bc9077c/types/react/v16/index.d.ts#L1025-L1039) or [mutable](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/abd69803c1b710db58d511f4544ec1b70bc9077c/types/react/v16/index.d.ts#L1012-L1023), depends on whether your type argument fully covers the initial value or not. Choose one that suits your use case.
+`useRef` always returns a `RefObject` in current `@types/react`. An initial value is required, and the returned `.current` is typed based on it. (`MutableRefObject` is deprecated and only kept for backwards compatibility.)
##### Option 1: DOM element ref
-**[To access a DOM element](https://reactjs.org/docs/refs-and-the-dom.html):** provide only the element type as argument, and use `null` as initial value. In this case, the returned reference will have a read-only `.current` that is managed by React. TypeScript expects you to give this ref to an element's `ref` prop:
+**To access a DOM element:** provide the element type as a generic and pass `null` as the initial value. React manages `.current` for you, and TypeScript expects you to pass this ref to an element's `ref` prop:
```tsx
function Foo() {
@@ -454,21 +458,30 @@ Refs demand specificity - it is not enough to just specify any old `HTMLElement`
##### Option 2: Mutable value ref
-**[To have a mutable value](https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables):** provide the type you want, and make sure the initial value fully belongs to that type:
+**To hold a mutable value across renders without re-rendering on change:** pass the initial value you want — React doesn't manage `.current` for you here, you write to it manually.
```tsx
function Foo() {
- // Technical-wise, this returns MutableRefObject
const intervalRef = useRef(null);
- // You manage the ref yourself (that's why it's called MutableRefObject!)
useEffect(() => {
- intervalRef.current = setInterval(...);
- return () => clearInterval(intervalRef.current);
+ intervalRef.current = window.setInterval(() => {
+ /* ... */
+ }, 1000);
+ return () => {
+ if (intervalRef.current !== null) clearInterval(intervalRef.current);
+ };
}, []);
- // The ref is not passed to any element's "ref" prop
- return ;
+ return (
+
+ );
}
```
@@ -479,19 +492,21 @@ function Foo() {
#### useImperativeHandle
-Based on this [Stackoverflow answer](https://stackoverflow.com/a/69292925/5415299):
+In React 19, `ref` is a regular prop on function components, so `useImperativeHandle` is called with the `ref` prop directly — no `forwardRef` needed.
```tsx
// Countdown.tsx
+import { useImperativeHandle, Ref } from "react";
-// Define the handle types which will be passed to the forwardRef
export type CountdownHandle = {
start: () => void;
};
-type CountdownProps = {};
+type CountdownProps = {
+ ref?: Ref;
+};
-const Countdown = forwardRef((props, ref) => {
+const Countdown = ({ ref }: CountdownProps) => {
useImperativeHandle(ref, () => ({
// start() has type inference here
start() {
@@ -500,12 +515,12 @@ const Countdown = forwardRef((props, ref) => {
}));
return
Countdown
;
-});
+};
```
```tsx
-// The component uses the Countdown component
-
+// The component using the Countdown component
+import { useEffect, useRef } from "react";
import Countdown, { CountdownHandle } from "./Countdown.tsx";
function App() {
@@ -522,9 +537,7 @@ function App() {
}
```
-##### See also:
-
-- [Using ForwardRefRenderFunction](https://stackoverflow.com/a/62258685/5415299)
+> If you still maintain code that targets React < 19, see the [forwardRef section](./forward-create-ref.md) for the legacy approach using `forwardRef`.
#### Custom Hooks
@@ -786,68 +799,38 @@ class Comp extends React.PureComponent {
-#### You May Not Need `defaultProps`
-
-As per [this tweet](https://twitter.com/dan_abramov/status/1133878326358171650), defaultProps will eventually be deprecated. You can check the discussions here:
-
-- [Original tweet](https://twitter.com/hswolff/status/1133759319571345408)
-- More info can also be found in [this article](https://medium.com/@matanbobi/react-defaultprops-is-dying-whos-the-contender-443c19d9e7f1)
+#### Function components
-The consensus is to use object default values.
-
-Function Components:
+As of React 19, `defaultProps` is **no longer supported on function components**. Use destructuring defaults directly in the parameter list — TypeScript will infer the prop as optional automatically:
```tsx
type GreetProps = { age?: number };
-const Greet = ({ age = 21 }: GreetProps) => // etc
-```
-
-Class Components:
-
-```tsx
-type GreetProps = {
- age?: number;
+const Greet = ({ age = 21 }: GreetProps) => {
+ // ...
};
-
-class Greet extends React.Component {
- render() {
- const { age = 21 } = this.props;
- /*...*/
- }
-}
-
-let el = ;
```
-#### Typing `defaultProps`
-
-Type inference improved greatly for `defaultProps` in [TypeScript 3.0+](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html), although [some edge cases are still problematic](https://github.com/typescript-cheatsheets/react/issues/61).
-
-**Function Components**
+If you prefer to declare defaults separately (for example, to share them across components), pull them into a constant and spread them when destructuring:
```tsx
-// using typeof as a shortcut; note that it hoists!
-// you can also declare the type of DefaultProps if you choose
-// e.g. https://github.com/typescript-cheatsheets/react/issues/415#issuecomment-841223219
-type GreetProps = { age: number } & typeof defaultProps;
+type GreetProps = { age?: number };
-const defaultProps = {
- age: 21,
-};
+const defaultProps = { age: 21 } satisfies GreetProps;
-const Greet = (props: GreetProps) => {
- // etc
+const Greet = ({ age = defaultProps.age }: GreetProps) => {
+ // ...
};
-Greet.defaultProps = defaultProps;
```
-_[See this in TS Playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAOKVYwAKxY6ALxwA3igDmWAFxwAdgFcQAIyxQ4AXzgAyOM1YQCcACZYCyeQBte-VPVwRZqeCbOXrEAXGEi6cCdLgAJgBGABo6dXo6e0d4TixuLzgACjAbGXjuPg9UAEovAD5RXzhKGHkoWTgAHiNgADcCkTScgDpkSTgAeiQFZVVELvVqrrrGiPpMmFaXcytsz2FZtwXbOiA)_
+> Setting `Greet.defaultProps = { age: 21 }` will not work on function components in React 19 — the value is ignored at runtime and `FunctionComponent` no longer types it.
-For **Class components**, there are [a couple ways to do it](https://github.com/typescript-cheatsheets/react/pull/103#issuecomment-481061483) (including using the `Pick` utility type) but the recommendation is to "reverse" the props definition:
+#### Class components
+
+Class components still support `static defaultProps`. The recommended approach is to type the props with the defaulted keys as required, and let `LibraryManagedAttributes` (applied automatically by JSX) make them optional at the call site:
```tsx
-type GreetProps = typeof Greet.defaultProps & {
+type GreetProps = {
age: number;
};
@@ -855,27 +838,28 @@ class Greet extends React.Component {
static defaultProps = {
age: 21,
};
- /*...*/
+
+ render() {
+ return
Hello, I am {this.props.age}
;
+ }
}
-// Type-checks! No type assertions needed!
-let el = ;
+// Type-checks — `age` is optional at the call site thanks to defaultProps.
+const el = ;
```
React.JSX.LibraryManagedAttributes nuance for library authors
-The above implementations work fine for App creators, but sometimes you want to be able to export `GreetProps` so that others can consume it. The problem here is that the way `GreetProps` is defined, `age` is a required prop when it isn't because of `defaultProps`.
-
-The insight to have here is that [`GreetProps` is the _internal_ contract for your component, not the _external_, consumer facing contract](https://github.com/typescript-cheatsheets/react/issues/66#issuecomment-453878710). You could create a separate type specifically for export, or you could make use of the `React.JSX.LibraryManagedAttributes` utility:
+If you export `GreetProps` for consumers, `age` will appear required even though `defaultProps` makes it optional at the call site. `GreetProps` is the _internal_ contract — there's a separate _external_ contract that JSX computes via `React.JSX.LibraryManagedAttributes`. You can compute it explicitly:
```tsx
-// internal contract, should not be exported out
+// internal contract — don't export
type GreetProps = {
age: number;
};
-class Greet extends Component {
+class Greet extends React.Component {
static defaultProps = { age: 21 };
}
@@ -886,109 +870,7 @@ export type ApparentGreetProps = React.JSX.LibraryManagedAttributes<
>;
```
-This will work properly, although hovering over`ApparentGreetProps`may be a little intimidating. You can reduce this boilerplate with the`ComponentProps` utility detailed below.
-
-
-
-#### Consuming Props of a Component with defaultProps
-
-A component with `defaultProps` may seem to have some required props that actually aren't.
-
-##### Problem Statement
-
-Here's what you want to do:
-
-```tsx
-interface IProps {
- name: string;
-}
-const defaultProps = {
- age: 25,
-};
-const GreetComponent = ({ name, age }: IProps & typeof defaultProps) => (
-
{`Hello, my name is ${name}, ${age}`}
-);
-GreetComponent.defaultProps = defaultProps;
-
-const TestComponent = (props: React.ComponentProps) => {
- return ;
-};
-
-// Property 'age' is missing in type '{ name: string; }' but required in type '{ age: number; }'
-const el = ;
-```
-
-##### Solution
-
-Define a utility that applies `React.JSX.LibraryManagedAttributes`:
-
-```tsx
-type ComponentProps = T extends
- | React.ComponentType
- | React.Component
- ? React.JSX.LibraryManagedAttributes
- : never;
-
-const TestComponent = (props: ComponentProps) => {
- return ;
-};
-
-// No error
-const el = ;
-```
-
-[_See this in TS Playground_](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAMImQB2W3MABWJhUAHgAqAPjgBeOOLhYAHjD4ATdNjwwAdJ3ARe-cSyyjg3AlihwB0gD6Yqu-Tz4xzl67cl04cAH44ACkAZQANHQAZYAAjKGQoJgBZZG5kAHMsNQBBGBgoOIBXVTFxABofPzgALjheADdrejoLVSgCPDYASSEIETgAb2r0kCw61AKLDPoAXzpcQ0m4NSxOooAbQWF0OWH-TPG4ACYAVnK6WfpF7mWAcUosGFdDd1k4AApB+uQxysO4LM6r0dnAAGRwZisCAEFZrZCbbb9VAASlk0g+1VEamADUkgwABgAJLAbDYQSogJg-MZwYDoAAkg1GWFmlSZh1mBNmogA9Di8XQUfQHlgni8jLpVustn0BnJpQjZTsWrzeXANsh2gwbstxFhJhK3nIPmAdnUjfw5WIoVgYXBReKuK9+JI0TJpPs4JQYEUoNw4KIABYARjgvN8VwYargADkIIooMQoAslvBSe8JAbns7JTSsDIyAQIBAyOHJDQgA)
-
-#### Misc Discussions and Knowledge
-
-
-Why does React.FC break defaultProps?
-
-You can check the discussions here:
-
-- https://medium.com/@martin_hotell/10-typescript-pro-tips-patterns-with-or-without-react-5799488d6680
-- https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30695
-- https://github.com/typescript-cheatsheets/react/issues/87
-
-This is just the current state and may be fixed in future.
-
-
-
-
-TypeScript 2.9 and earlier
-
-For TypeScript 2.9 and earlier, there's more than one way to do it, but this is the best advice we've yet seen:
-
-```ts
-type Props = Required & {
- /* additional props here */
-};
-
-export class MyComponent extends React.Component {
- static defaultProps = {
- foo: "foo",
- };
-}
-```
-
-Our former recommendation used the `Partial type` feature in TypeScript, which means that the current interface will fulfill a partial version on the wrapped interface. In that way we can extend defaultProps without any changes in the types!
-
-```ts
-interface IMyComponentProps {
- firstProp?: string;
- secondProp: IPerson[];
-}
-
-export class MyComponent extends React.Component {
- public static defaultProps: Partial = {
- firstProp: "default",
- };
-}
-```
-
-The problem with this approach is it causes complex issues with the type inference working with `React.JSX.LibraryManagedAttributes`. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional.
-
-[See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react/issues/57) and [here](https://github.com/typescript-cheatsheets/react/issues/61).
+For most apps this isn't needed — only library authors who re-export the props type tend to hit it.
@@ -1370,7 +1252,7 @@ type ThemeContextType = "light" | "dark";
const ThemeContext = createContext("light");
```
-Wrap the components that need the context with a context provider:
+Wrap the components that need the context by rendering the context itself as a provider. In React 19, the context object can be rendered directly — you no longer need ``:
```tsx
import { useState } from "react";
@@ -1379,25 +1261,29 @@ const App = () => {
const [theme, setTheme] = useState("light");
return (
-
+
-
+
);
};
```
-Call `useContext` to read and subscribe to the context.
+> `` still works and is identical in behavior — it's just the legacy spelling.
+
+Read the context with `use`:
```tsx
-import { useContext } from "react";
+import { use } from "react";
const MyComponent = () => {
- const theme = useContext(ThemeContext);
+ const theme = use(ThemeContext);
return
The current theme is {theme}.
;
};
```
+> `useContext(ThemeContext)` still works too. The main difference is that `use` can also unwrap a promise, and it can be called inside conditions and loops.
+
#### Without default context value
If you don't have any meaningful default value, specify `null`:
@@ -1419,9 +1305,9 @@ const App = () => {
});
return (
-
+
-
+
);
};
```
@@ -1429,10 +1315,10 @@ const App = () => {
Now that the type of the context can be `null`, you'll notice that you'll get a `'currentUser' is possibly 'null'` TypeScript error if you try to access the `username` property. You can use optional chaining to access `username`:
```tsx
-import { useContext } from "react";
+import { use } from "react";
const MyComponent = () => {
- const currentUser = useContext(CurrentUserContext);
+ const currentUser = use(CurrentUserContext);
return
Name: {currentUser?.username}.
;
};
@@ -1441,7 +1327,7 @@ const MyComponent = () => {
However, it would be preferable to not have to check for `null`, since we know that the context won't be `null`. One way to do that is to provide a custom hook to use the context, where an error is thrown if the context is not provided:
```tsx
-import { createContext } from "react";
+import { createContext, use } from "react";
interface CurrentUserContextType {
username: string;
@@ -1450,11 +1336,11 @@ interface CurrentUserContextType {
const CurrentUserContext = createContext(null);
const useCurrentUser = () => {
- const currentUserContext = useContext(CurrentUserContext);
+ const currentUserContext = use(CurrentUserContext);
if (!currentUserContext) {
throw new Error(
- "useCurrentUser has to be used within "
+ "useCurrentUser has to be used within "
);
}
@@ -1465,8 +1351,6 @@ const useCurrentUser = () => {
Using a runtime type check in this will have the benefit of printing a clear error message in the console when a provider is not wrapping the components properly. Now it's possible to access `currentUser.username` without checking for `null`:
```tsx
-import { useContext } from "react";
-
const MyComponent = () => {
const currentUser = useCurrentUser();
@@ -1479,10 +1363,10 @@ const MyComponent = () => {
Another way to avoid having to check for `null` is to use type assertion to tell TypeScript you know the context is not `null`:
```tsx
-import { useContext } from "react";
+import { use } from "react";
const MyComponent = () => {
- const currentUser = useContext(CurrentUserContext);
+ const currentUser = use(CurrentUserContext);
return
Name: {currentUser!.username}.
;
};
@@ -1904,9 +1788,154 @@ export default ErrorBoundary;
-#### Concurrent React/React Suspense
+#### Concurrent React
+
+The Concurrent React APIs (`Suspense`, `useTransition`, `useDeferredValue`, `startTransition`, `use`) let you keep the UI responsive while React renders work in the background or waits for data. They're all stable as of React 18 and gained additional capabilities in React 19.
+
+#### `Suspense`
+
+`Suspense` lets you declaratively show a fallback while a child component is waiting for something — typically data unwrapped with `use(promise)`, a lazy component, or a streamed boundary on the server.
+
+```tsx
+import { Suspense } from "react";
+
+const UserProfile = ({ userPromise }: { userPromise: Promise }) => {
+ const user = use(userPromise);
+ return
}>
+
+
+);
+```
+
+`SuspenseProps` is typed as `{ children?: ReactNode; fallback?: ReactNode }`. The fallback can be any `ReactNode`, including `null`.
+
+#### `use`
+
+`use` reads the value of a context or a promise. Unlike `useContext`, it can be called inside conditions and loops, and it integrates with `Suspense` for promises.
+
+```tsx
+import { use } from "react";
+
+const Comments = ({
+ commentsPromise,
+}: {
+ commentsPromise: Promise;
+}) => {
+ // Suspends until the promise resolves; throws to the nearest .
+ const comments = use(commentsPromise);
+ return (
+
+ {comments.map((c) => (
+
{c.text}
+ ))}
+
+ );
+};
+```
+
+The promise is typically created by a parent and passed down — don't create it inside the component, or you'll create a new promise on every render.
+
+#### `useTransition`
+
+`useTransition` marks a state update as non-urgent so React can keep typing, scrolling, and other urgent input responsive while it renders.
+
+```tsx
+import { useState, useTransition } from "react";
+
+const TabSwitcher = () => {
+ const [isPending, startTransition] = useTransition();
+ const [tab, setTab] = useState<"posts" | "comments">("posts");
+
+ const selectTab = (next: "posts" | "comments") => {
+ startTransition(() => {
+ setTab(next);
+ });
+ };
+
+ return (
+ <>
+
+
+ {tab === "posts" ? : }
+ >
+ );
+};
+```
+
+##### Async transitions (React 19)
+
+In React 19, the function passed to `startTransition` can be async. This is the foundation for Actions and is how `useActionState` and `;
+}
+```
+
+## `ReactNode` vs `ReactElement` vs `JSX.Element`
+
+These three types are often confused because all three appear when you write JSX. They are not interchangeable:
+
+- **`ReactNode`** is the broadest: anything React can render, including primitives, `null`, arrays, and elements.
+- **`ReactElement`** describes only the object produced by JSX or `createElement` — it has `type`, `props`, and `key`. A `string` is _not_ a `ReactElement`.
+- **`React.JSX.Element`** is essentially `ReactElement` — what the JSX transform infers for a JSX expression.
+
+### Use `ReactNode` for `children`
+
+`ReactNode` is the correct type for any prop that receives children-like content, because a caller might pass a string, an array, or `null`:
+
+```tsx
+type Props = { content: ReactNode };
+
+ // ✅ string is a ReactNode
+hi} /> // ✅ element is a ReactNode
+ // ✅ null is a ReactNode
+```
+
+### Don't use `ReactNode` as a function-component return type
+
+A function component's return type should be what React allows components to _return_, not what it allows them to _receive_. Returning a plain `ReactNode` (which includes `bigint`, `Promise`, etc.) is broader than what TypeScript wants to see from a JSX-rendered component. Let TypeScript infer the return type, or use `React.JSX.Element` / `ReactElement` if you must annotate:
+
+```tsx
+// 👎 too broad, and historically caused issues when used in JSX
+const MyComponent = (): ReactNode => "hello";
+
+// 👍 let TS infer
+const MyComponent = () => "hello";
+
+// 👍 explicit
+const MyComponent = (): React.JSX.Element => hello;
+```
+
+[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new).
diff --git a/docs/react-types/Ref.md b/docs/react-types/Ref.md
new file mode 100644
index 000000000..ea9b2968a
--- /dev/null
+++ b/docs/react-types/Ref.md
@@ -0,0 +1,120 @@
+---
+title: Ref, RefObject, RefCallback
+---
+
+`@types/react` ships three closely related ref types. Understanding how they fit together is the key to typing refs correctly in React 19, where `ref` is a regular prop on function components.
+
+| Type | What it is | When to use |
+| ---------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
+| `RefObject` | An object with a `current: T` field. | Return type of `useRef` and `createRef`. Pass it as `ref={…}` to read/write `.current`. |
+| `RefCallback` | A function that receives the instance (or `null` on unmount). | Inline `ref={node => …}` callbacks. May return a cleanup function in React 19+. |
+| `Ref` | `RefCallback \| RefObject \| null`. | Use this as the **prop type** when accepting a ref from a parent — the parent might pass either form. |
+
+```ts
+interface RefObject {
+ current: T;
+}
+
+type RefCallback = (instance: T | null) => void | (() => void);
+
+type Ref = RefCallback | RefObject | null;
+```
+
+## `RefObject`
+
+`RefObject` is what `useRef` and `createRef` return. Its `.current` is typed based on the initial value you pass:
+
+```tsx
+import { useRef } from "react";
+
+const inputRef = useRef(null);
+// ^? RefObject
+
+const idRef = useRef(0);
+// ^? RefObject
+```
+
+When you pass `null` as the initial value with an explicit generic, React manages `.current` for you — TypeScript types it as `T | null` so you have to null-check before use:
+
+```tsx
+useEffect(() => {
+ inputRef.current?.focus();
+}, []);
+```
+
+> `MutableRefObject` still exists in `@types/react` for backwards compatibility but is `@deprecated` — use `RefObject` instead.
+
+## `RefCallback`
+
+Callback refs are useful when you need to run code the moment the DOM node is attached or detached. The callback is called with the node when it mounts, and with `null` when it unmounts:
+
+```tsx
+
{
+ if (node) console.log("mounted", node);
+ else console.log("unmounted");
+ }}
+/>
+```
+
+### Cleanup function (React 19)
+
+In React 19, a ref callback can return a cleanup function — React calls it instead of invoking the callback again with `null`. This makes ref callbacks symmetric with `useEffect`:
+
+```tsx
+
{
+ const observer = new IntersectionObserver(/* ... */);
+ observer.observe(node);
+ return () => observer.disconnect();
+ }}
+/>
+```
+
+If your callback returns nothing, React falls back to the old behavior and calls it with `null` on unmount.
+
+## `Ref` (the union)
+
+`Ref` is the type you should use when **accepting** a ref as a prop, because a caller can pass either a `RefObject` or a callback.
+
+```tsx
+import { Ref } from "react";
+
+type FancyInputProps = {
+ ref?: Ref;
+ placeholder?: string;
+};
+
+function FancyInput({ ref, placeholder }: FancyInputProps) {
+ return ;
+}
+```
+
+In React 19 this is all you need — `ref` is a regular prop, no `forwardRef` wrapper required.
+
+### Forwarding a ref to a different element
+
+If the ref you accept doesn't belong on the root element, you can still pass it down — `Ref` is assignable to any element's `ref` prop as long as `T` matches:
+
+```tsx
+type LabelledInputProps = {
+ label: string;
+ ref?: Ref;
+};
+
+function LabelledInput({ label, ref }: LabelledInputProps) {
+ return (
+
+ );
+}
+```
+
+## Related types
+
+- **`ForwardedRef`** — the legacy `ref` parameter type passed to a `forwardRef` render function. Only relevant if you still use `forwardRef`; prefer `Ref` on a prop instead.
+- **`LegacyRef`** — `@deprecated` alias for `Ref`. String refs are no longer supported.
+- **`ComponentRef`** — the ref type accepted by a given component or element, e.g. `ComponentRef<"input">` is `HTMLInputElement`. Useful when you want the ref type without writing it out by hand.
+- **`RefAttributes`** — the prop shape `{ ref?: Ref }`. Rarely needed directly; intersected by `ComponentPropsWithRef`.
diff --git a/docs/react-types/index.md b/docs/react-types/index.md
index 55e76caea..4d86ede51 100644
--- a/docs/react-types/index.md
+++ b/docs/react-types/index.md
@@ -5,4 +5,6 @@ title: React Types
`@types/react` makes some types available that can be very useful. Here's a list in alphabetical order with links to the detailed reference pages.
- [`ComponentProps`](/docs/react-types/ComponentProps)
+- [`CSSProperties`](/docs/react-types/CSSProperties)
- [`ReactNode`](/docs/react-types/ReactNode)
+- [`Ref`, `RefObject`, `RefCallback`](/docs/react-types/Ref)