diff --git a/apps/docs-v2/app/routes/_docs.input-types.mdx b/apps/docs-v2/app/routes/_docs.input-types.mdx
index 8552a5f5..698b3c0e 100644
--- a/apps/docs-v2/app/routes/_docs.input-types.mdx
+++ b/apps/docs-v2/app/routes/_docs.input-types.mdx
@@ -46,16 +46,16 @@ that you would get out of `form.value("myField")`.
## Number inputs
+### Relevant types
+
+- `NumberInputValue`
+ - `number | null`
+
### Setting default values
- - Number inputs can be set using either a `number` or a `string`,
- and both approaches can be used for different fields in the same form.
- - When you access the value of the input using `form.value("age")`, the type
- of that value will be consistent with the type of the default value, even after
- the user has changed the value.
- - If there is no default value, the type of the value will be a `number`.
+ Number inputs can be set using either a `number`, a `string`, or `null`.
```tsx
@@ -75,6 +75,12 @@ that you would get out of `form.value("myField")`.
+### Observing / setting values
+
+- An empty number input will always have a value of `null`.
+- If you set the default value using a `string`, the value will always be a `string` (or `null`).
+- If you set the default value using a `number` or `null`, the value will always be a `number` (or `null`).
+
### Validating
Like most input types, the value inside the native `form` element is always a string.
diff --git a/apps/docs-v2/app/routes/_docs.recipes.typesafe-input.mdx b/apps/docs-v2/app/routes/_docs.recipes.typesafe-input.mdx
new file mode 100644
index 00000000..6fb9327f
--- /dev/null
+++ b/apps/docs-v2/app/routes/_docs.recipes.typesafe-input.mdx
@@ -0,0 +1 @@
+# Typesafe input component
diff --git a/apps/docs-v2/app/routes/_docs.scoping.mdx b/apps/docs-v2/app/routes/_docs.scoping.mdx
index 8f6025de..3c7576fd 100644
--- a/apps/docs-v2/app/routes/_docs.scoping.mdx
+++ b/apps/docs-v2/app/routes/_docs.scoping.mdx
@@ -19,12 +19,12 @@ code in this demo.
When you call `useForm`, it returns a [`ReactFormApi`](/reference/form-api) object.
- The type of this object takes a single generic paramter, which is the type of the default values.
+ The type of this object takes a single generic parameter, which is the type of the form's default values.
```tsx
// `form` has the type `ReactFormApi<{ foo: string }>`
- const form = useForm({
+ const form = useForm({
defaultValues: { foo: "bar" },
// ...etc
});
@@ -35,13 +35,16 @@ code in this demo.
One of the methods on `ReactFormApi` is `scope`.
- When you call `scope` and pass it the name of a field, it returns a `FormScope`
- where `FieldType` is the type of the field.
+ When you call `scope` and pass it the name of a field, it returns a `FormScope`
+ that's been scoped to that field.
You can even continue chaining `scope` calls to get even deeper, which is useful for deeply nested or recursive data.
+
+ Once you have a `FormScope`, you can pass it around to any component that needs it.
+ But in order to actually use it, you need to pass it to a `useFormScope`, `useField`, or `useFieldArray` hook.
```tsx
- const form = useForm({
+ const form = useForm({
defaultValues: {
foo: "foo",
bar: { baz: "baz" }
@@ -61,3 +64,48 @@ code in this demo.
+
+## Typesafe text input
+
+
+
+ Scoping allows us to encapsulate input logic in a typesafe way.
+ For this example, let's create an text input component that:
+
+ - Is guranteed by the types to have a `string` value.
+ - Automatically shows the validation error message if there is one.
+ - Can be used without having to think about whether to use `getInputProps` or `getControlProps`.
+
+ We can do this by accepting a `FormScope<string>` as a prop
+ and passing it to `useField`.
+
+
+