diff --git a/src/React.bs.js b/src/React.bs.js
index c2471b6..ef827dd 100644
--- a/src/React.bs.js
+++ b/src/React.bs.js
@@ -3,8 +3,6 @@
 
 var React = require("react");
 
-var Ref = {};
-
 var Children = {};
 
 var Context = {};
@@ -25,7 +23,6 @@ function lazy_(load) {
 
 var Uncurried = {};
 
-exports.Ref = Ref;
 exports.Children = Children;
 exports.Context = Context;
 exports.Fragment = Fragment;
diff --git a/src/React.res b/src/React.res
index 0beaa59..f1f6831 100644
--- a/src/React.res
+++ b/src/React.res
@@ -5,6 +5,7 @@ type element = Jsx.element
 external float: float => element = "%identity"
 external int: int => element = "%identity"
 external string: string => element = "%identity"
+external promise: promise<element> => element = "%identity"
 
 external array: array<element> => element = "%identity"
 
@@ -250,6 +251,9 @@ external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback =
 @module("react")
 external useContext: Context.t<'any> => 'any = "useContext"
 
+@module("react")
+external usePromise: promise<'a> => 'a = "use"
+
 @module("react") external useRef: 'value => ref<'value> = "useRef"
 
 @module("react")
@@ -309,10 +313,9 @@ external useImperativeHandle7: (
 
 @module("react") external useId: unit => string = "useId"
 
-@module("react") external useDeferredValue: 'value => 'value = "useDeferredValue"
-
+/** `useDeferredValue` is a React Hook that lets you defer updating a part of the UI. */
 @module("react")
-external useTransition: unit => (bool, (unit => unit) => unit) = "useTransition"
+external useDeferredValue: ('value, ~initialValue: 'value=?) => 'value = "useDeferredValue"
 
 @module("react")
 external useInsertionEffectOnEveryRender: (unit => option<unit => unit>) => unit =
@@ -405,3 +408,36 @@ external setDisplayName: (component<'props>, string) => unit = "displayName"
 
 @get @return(nullable)
 external displayName: component<'props> => option<string> = "displayName"
+
+// Actions
+
+type transitionFunction = unit => promise<unit>
+
+type transitionStartFunction = transitionFunction => unit
+
+/** `useTransition` is a React Hook that lets you render a part of the UI in the background. */
+@module("react")
+external useTransition: unit => (bool, transitionStartFunction) = "useTransition"
+
+type action<'state, 'payload> = ('state, 'payload) => promise<'state>
+
+type formAction<'formData> = 'formData => promise<unit>
+
+/** `useActionState` is a Hook that allows you to update state based on the result of a form action. */
+@module("react")
+external useActionState: (
+  action<'state, 'payload>,
+  'state,
+  ~permalink: string=?,
+) => ('state, formAction<'payload>, bool) = "useActionState"
+
+/** `useOptimistic` is a React Hook that lets you optimistically update the UI. */
+@module("react")
+external useOptimistic: (
+  'state,
+  ~updateFn: ('state, 'action) => 'state=?,
+) => ('state, 'action => unit) = "useOptimistic"
+
+/** `act` is a test helper to apply pending React updates before making assertions. */
+@module("react")
+external act: (unit => promise<unit>) => promise<unit> = "act"
diff --git a/src/ReactDOM.bs.js b/src/ReactDOM.bs.js
index b65084d..fa51640 100644
--- a/src/ReactDOM.bs.js
+++ b/src/ReactDOM.bs.js
@@ -1,6 +1,7 @@
 // Generated by ReScript, PLEASE EDIT WITH CARE
 'use strict';
 
+var Caml_option = require("rescript/lib/js/caml_option.js");
 
 var Root = {};
 
@@ -8,14 +9,50 @@ var Client = {
   Root: Root
 };
 
-var Ref = {};
+function getString(formData, name) {
+  var value = formData.get(name);
+  if (!(value == null) && typeof value === "string") {
+    return Caml_option.some(value);
+  }
+  
+}
+
+function getFile(formData, name) {
+  var value = formData.get(name);
+  if (!(value == null) && typeof value !== "string") {
+    return Caml_option.some(value);
+  }
+  
+}
+
+function getAll(t, string) {
+  return t.getAll(string).map(function (value) {
+              if (typeof value === "string") {
+                return {
+                        TAG: "String",
+                        _0: value
+                      };
+              } else {
+                return {
+                        TAG: "File",
+                        _0: value
+                      };
+              }
+            });
+}
 
-var Props = {};
+var $$FormData = {
+  getString: getString,
+  getFile: getFile,
+  getAll: getAll
+};
+
+var Ref = {};
 
 var Style;
 
 exports.Client = Client;
+exports.$$FormData = $$FormData;
 exports.Ref = Ref;
-exports.Props = Props;
 exports.Style = Style;
 /* No side effect */
diff --git a/src/ReactDOM.res b/src/ReactDOM.res
index 04c39c2..fbd564b 100644
--- a/src/ReactDOM.res
+++ b/src/ReactDOM.res
@@ -25,6 +25,52 @@ module Client = {
   external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot"
 }
 
+// Very rudimentary form data bindings
+module FormData = {
+  type t
+  type file
+
+  type formValue =
+    | String(string)
+    | File(file)
+
+  @new external make: unit => t = "FormData"
+
+  @send external append: (t, string, ~filename: string=?) => unit = "append"
+  @send external delete: (t, string) => unit = "delete"
+  @return(nullable) @send external getUnsafe: (t, string) => option<'a> = "get"
+  @send external getAllUnsafe: (t, string) => array<'a> = "getAll"
+
+  let getString = (formData, name) => {
+    switch formData->getUnsafe(name) {
+    | Some(value) => Js.typeof(value) === "string" ? Some(value) : None
+    | _ => None
+    }
+  }
+
+  external _asFile: 'a => file = "%identity"
+
+  let getFile = (formData, name) => {
+    switch formData->getUnsafe(name) {
+    | Some(value) => Js.typeof(value) === "string" ? None : Some(value->_asFile)
+    | _ => None
+    }
+  }
+
+  let getAll = (t, string) => {
+    t
+    ->getAllUnsafe(string)
+    ->Js.Array2.map(value => {
+      Js.typeof(value) === "string" ? String(value) : File(value->_asFile)
+    })
+  }
+
+  @send external set: (string, string) => unit = "set"
+  @send external has: string => bool = "has"
+  // @send external keys: t => Iterator.t<string> = "keys";
+  // @send external values: t => Iterator.t<value> = "values";
+}
+
 @module("react-dom")
 external createPortal: (React.element, Dom.element) => React.element = "createPortal"
 
@@ -37,12 +83,142 @@ type domRef = JsxDOM.domRef
 module Ref = {
   type t = domRef
   type currentDomRef = React.ref<Js.nullable<Dom.element>>
-  type callbackDomRef = Js.nullable<Dom.element> => unit
+  type callbackDomRef = Js.nullable<Dom.element> => option<unit => unit>
 
   external domRef: currentDomRef => domRef = "%identity"
   external callbackDomRef: callbackDomRef => domRef = "%identity"
 }
 
+// Hooks
+
+type formStatus<'state> = {
+  /** If true, this means the parent <form> is pending submission. Otherwise, false. */
+  pending: bool,
+  /** An object implementing the FormData interface that contains the data the parent <form> is submitting. If there is no active submission or no parent <form>, it will be null. */
+  data: FormData.t,
+  /** This represents whether the parent <form> is submitting with either a GET or POST HTTP method. By default, a <form> will use the GET method and can be specified by the method property. */
+  method: [#get | #post],
+  /** A reference to the function passed to the action prop on the parent <form>. If there is no parent <form>, the property is null. If there is a URI value provided to the action prop, or no action prop specified, status.action will be null. */
+  action: React.action<'state, FormData.t>,
+}
+
+external formAction: React.formAction<FormData.t> => string = "%identity"
+
+/** `useFormStatus` is a Hook that gives you status information of the last form submission. */
+@module("react-dom")
+external useFormStatus: unit => formStatus<'state> = "useFormStatus"
+
+// Resource Preloading APIs
+
+/** The CORS policy to use. */
+type crossOrigin = [
+  | #anonymous
+  | #"use-credentials"
+]
+
+/** The Referrer header to send when fetching. */
+type referrerPolicy = [
+  | #"referrer-when-downgrade"
+  | #"no-referrer"
+  | #origin
+  | #"origin-when-cross-origin"
+  | #"unsafe-url"
+]
+
+/** Suggests a relative priority for fetching the resource. */
+type fetchPriority = [#auto | #high | #low]
+
+/** `prefetchDNS` lets you eagerly look up the IP of a server that you expect to load resources from. */
+@module("react-dom")
+external prefetchDNS: string => unit = "prefetchDNS"
+
+/** `preconnect` lets you eagerly connect to a server that you expect to load resources from. */
+@module("react-dom")
+external preconnect: string => unit = "preconnect"
+
+type preloadOptions = {
+  /** The type of resource. */
+  @as("as")
+  as_: [
+    | #audio
+    | #document
+    | #embed
+    | #fetch
+    | #font
+    | #image
+    | #object
+    | #script
+    | #style
+    | #track
+    | #video
+    | #worker
+  ],
+  /** The CORS policy to use. It is required when as is set to "fetch". */
+  crossOrigin?: crossOrigin,
+  /** The Referrer header to send when fetching. */
+  referrerPolicy?: referrerPolicy,
+  /** A cryptographic hash of the resource, to verify its authenticity. */
+  integrity?: string,
+  /** The MIME type of the resource. */
+  @as("type")
+  type_?: string,
+  /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */
+  nonce?: string,
+  /** Suggests a relative priority for fetching the resource. */
+  fetchPriority?: fetchPriority,
+  /** For use only with as: "image". Specifies the source set of the image. */
+  imageSrcSet?: string,
+  /** For use only with as: "image". Specifies the sizes of the image. */
+  imageSizes?: string,
+}
+
+/** `preload` lets you eagerly fetch a resource such as a stylesheet, font, or external script that you expect to use. */
+@module("react-dom")
+external preload: (string, preloadOptions) => unit = "preload"
+
+type preloadModuleOptions = {
+  /** The type of resource. */
+  @as("as")
+  as_: [#script],
+  /** The CORS policy to use. It is required when as is set to "fetch". */
+  crossOrigin?: crossOrigin,
+  /** A cryptographic hash of the resource, to verify its authenticity. */
+  integrity?: string,
+  /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */
+  nonce?: string,
+}
+
+/** `preloadModule` lets you eagerly fetch an ESM module that you expect to use. */
+@module("react-dom")
+external preloadModule: (string, preloadModuleOptions) => unit = "preloadModule"
+
+type preinitOptions = {
+  /** The type of resource. */
+  @as("as")
+  as_: [#script | #style],
+  /** Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. */
+  precedence?: [#reset | #low | #medium | #high],
+  /** The CORS policy to use. It is required when as is set to "fetch". */
+  crossOrigin?: crossOrigin,
+  /** The Referrer header to send when fetching. */
+  referrerPolicy?: referrerPolicy,
+  /** A cryptographic hash of the resource, to verify its authenticity. */
+  integrity?: string,
+  nonce?: string,
+  /** Suggests a relative priority for fetching the resource. */
+  fetchPriority?: fetchPriority,
+}
+
+/** `preinit` lets you eagerly fetch and evaluate a stylesheet or external script. */
+@module("react-dom")
+external preinit: (string, preinitOptions) => unit = "preinit"
+
+/** To preinit an ESM module, call the `preinitModule` function from react-dom. */
+@module("react-dom")
+external preinitModule: (string, preloadModuleOptions) => unit = "preinitModule"
+
+// Runtime
+
 type domProps = JsxDOM.domProps
 
 @variadic @module("react")
diff --git a/src/ReactDOMStatic.bs.js b/src/ReactDOMStatic.bs.js
new file mode 100644
index 0000000..d856702
--- /dev/null
+++ b/src/ReactDOMStatic.bs.js
@@ -0,0 +1,2 @@
+// Generated by ReScript, PLEASE EDIT WITH CARE
+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
diff --git a/src/ReactDOMStatic.res b/src/ReactDOMStatic.res
new file mode 100644
index 0000000..7988fbb
--- /dev/null
+++ b/src/ReactDOMStatic.res
@@ -0,0 +1,30 @@
+type abortSignal // WebAPI.EventAPI.abortSignal
+
+type nodeStream // NodeJs.Stream.stream
+
+type readableStream // WebAPI.FileAPI.readableStream
+
+type prerenderOptions<'error> = {
+  bootstrapScriptContent?: string,
+  bootstrapScripts?: array<string>,
+  bootstrapModules?: array<string>,
+  identifierPrefix?: string,
+  namespaceURI?: string,
+  onError?: 'error => unit,
+  progressiveChunkSize?: int,
+  signal?: abortSignal,
+}
+
+type staticResult = {prelude: readableStream}
+
+@module("react-dom/static")
+external prerender: (React.element, ~options: prerenderOptions<'error>=?) => promise<staticResult> =
+  "prerender"
+
+type staticResultNode = {prelude: nodeStream}
+
+@module("react-dom/static")
+external prerenderToNodeStream: (
+  React.element,
+  ~options: prerenderOptions<'error>=?,
+) => promise<staticResultNode> = "prerenderToNodeStream"