diff --git a/examples/solid/array/package.json b/examples/solid/array/package.json
index cf1369b1b..c6197cb64 100644
--- a/examples/solid/array/package.json
+++ b/examples/solid/array/package.json
@@ -10,11 +10,12 @@
},
"dependencies": {
"@tanstack/solid-form": "^1.33.0",
- "solid-js": "^1.9.9"
+ "solid-js": "2.0.0-beta.15"
},
"devDependencies": {
+ "@solidjs/web": "2.0.0-beta.15",
"typescript": "5.9.3",
"vite": "^7.2.2",
- "vite-plugin-solid": "^2.11.8"
+ "vite-plugin-solid": "3.0.0-next.5"
}
}
diff --git a/examples/solid/array/src/index.tsx b/examples/solid/array/src/index.tsx
index e930e712c..9dae886fb 100644
--- a/examples/solid/array/src/index.tsx
+++ b/examples/solid/array/src/index.tsx
@@ -1,8 +1,8 @@
/* @refresh reload */
-import { render } from 'solid-js/web'
+import { render } from '@solidjs/web'
import { createForm } from '@tanstack/solid-form'
-import { Index, Show } from 'solid-js'
+import { Repeat, Show } from 'solid-js'
function App() {
const form = createForm(() => ({
@@ -26,8 +26,8 @@ function App() {
0}>
{/* Do not change this to For or the test will fail */}
-
- {(_, i) => (
+
+ {(i) => (
{(subField) => (
@@ -44,7 +44,7 @@ function App() {
)}
)}
-
+
)
diff --git a/examples/solid/large-form/src/index.tsx b/examples/solid/large-form/src/index.tsx
index f764172a5..6813299d3 100644
--- a/examples/solid/large-form/src/index.tsx
+++ b/examples/solid/large-form/src/index.tsx
@@ -1,4 +1,4 @@
-import { render } from 'solid-js/web'
+import { render } from '@solidjs/web'
import App from './App.tsx'
const root = document.getElementById('root')
diff --git a/examples/solid/large-form/tsconfig.json b/examples/solid/large-form/tsconfig.json
index 5e559e80f..2d91c4727 100644
--- a/examples/solid/large-form/tsconfig.json
+++ b/examples/solid/large-form/tsconfig.json
@@ -12,7 +12,7 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
- "jsxImportSource": "solid-js",
+ "jsxImportSource": "@solidjs/web",
/* Linting */
"strict": true,
"noUnusedLocals": true,
diff --git a/examples/solid/multi-step-wizard/package.json b/examples/solid/multi-step-wizard/package.json
index 61eef3612..487180e81 100644
--- a/examples/solid/multi-step-wizard/package.json
+++ b/examples/solid/multi-step-wizard/package.json
@@ -10,12 +10,13 @@
},
"dependencies": {
"@tanstack/solid-form": "^1.33.0",
- "solid-js": "^1.9.9",
+ "solid-js": "2.0.0-beta.15",
"zod": "^3.25.76"
},
"devDependencies": {
+ "@solidjs/web": "2.0.0-beta.15",
"typescript": "5.9.3",
"vite": "^7.2.2",
- "vite-plugin-solid": "^2.11.8"
+ "vite-plugin-solid": "3.0.0-next.5"
}
}
diff --git a/examples/solid/multi-step-wizard/src/index.tsx b/examples/solid/multi-step-wizard/src/index.tsx
index 88bb10c6c..0743af72c 100644
--- a/examples/solid/multi-step-wizard/src/index.tsx
+++ b/examples/solid/multi-step-wizard/src/index.tsx
@@ -1,5 +1,5 @@
/* @refresh reload */
-import { render } from 'solid-js/web'
+import { render } from '@solidjs/web'
import { WizardPage } from './features/wizard/page.tsx'
function App() {
diff --git a/examples/solid/multi-step-wizard/tsconfig.json b/examples/solid/multi-step-wizard/tsconfig.json
index 576a7f010..26e9875fe 100644
--- a/examples/solid/multi-step-wizard/tsconfig.json
+++ b/examples/solid/multi-step-wizard/tsconfig.json
@@ -13,7 +13,7 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
- "jsxImportSource": "solid-js",
+ "jsxImportSource": "@solidjs/web",
/* Linting */
"strict": true,
diff --git a/examples/solid/simple/package.json b/examples/solid/simple/package.json
index 0b2220400..99de44841 100644
--- a/examples/solid/simple/package.json
+++ b/examples/solid/simple/package.json
@@ -10,11 +10,12 @@
},
"dependencies": {
"@tanstack/solid-form": "^1.33.0",
- "solid-js": "^1.9.9"
+ "solid-js": "2.0.0-beta.15"
},
"devDependencies": {
+ "@solidjs/web": "2.0.0-beta.15",
"typescript": "5.9.3",
"vite": "^7.2.2",
- "vite-plugin-solid": "^2.11.8"
+ "vite-plugin-solid": "3.0.0-next.5"
}
}
diff --git a/examples/solid/simple/src/index.tsx b/examples/solid/simple/src/index.tsx
index e74faded7..68308a771 100644
--- a/examples/solid/simple/src/index.tsx
+++ b/examples/solid/simple/src/index.tsx
@@ -1,5 +1,5 @@
/* @refresh reload */
-import { render } from 'solid-js/web'
+import { render } from '@solidjs/web'
import { createForm } from '@tanstack/solid-form'
import type { AnyFieldApi } from '@tanstack/solid-form'
diff --git a/examples/solid/simple/tsconfig.json b/examples/solid/simple/tsconfig.json
index 576a7f010..26e9875fe 100644
--- a/examples/solid/simple/tsconfig.json
+++ b/examples/solid/simple/tsconfig.json
@@ -13,7 +13,7 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
- "jsxImportSource": "solid-js",
+ "jsxImportSource": "@solidjs/web",
/* Linting */
"strict": true,
diff --git a/examples/solid/standard-schema/package.json b/examples/solid/standard-schema/package.json
index ea0b81ed9..ab5dcbfcc 100644
--- a/examples/solid/standard-schema/package.json
+++ b/examples/solid/standard-schema/package.json
@@ -14,13 +14,14 @@
"effect": "^3.17.14",
"react": "19.1.0",
"react-dom": "19.1.0",
- "solid-js": "^1.9.9",
+ "solid-js": "2.0.0-beta.15",
"valibot": "^1.1.0",
"zod": "^3.25.76"
},
"devDependencies": {
+ "@solidjs/web": "2.0.0-beta.15",
"typescript": "5.9.3",
"vite": "^7.2.2",
- "vite-plugin-solid": "^2.11.8"
+ "vite-plugin-solid": "3.0.0-next.5"
}
}
diff --git a/examples/solid/standard-schema/src/index.tsx b/examples/solid/standard-schema/src/index.tsx
index db7533c6f..659bd445d 100644
--- a/examples/solid/standard-schema/src/index.tsx
+++ b/examples/solid/standard-schema/src/index.tsx
@@ -1,5 +1,5 @@
/* @refresh reload */
-import { render } from 'solid-js/web'
+import { render } from '@solidjs/web'
import { createForm } from '@tanstack/solid-form'
diff --git a/examples/solid/standard-schema/tsconfig.json b/examples/solid/standard-schema/tsconfig.json
index 850d4bf2e..36a794c18 100644
--- a/examples/solid/standard-schema/tsconfig.json
+++ b/examples/solid/standard-schema/tsconfig.json
@@ -13,7 +13,7 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
- "jsxImportSource": "solid-js",
+ "jsxImportSource": "@solidjs/web",
/* Linting */
"strict": true,
diff --git a/package.json b/package.json
index 190c8dc88..02c172e64 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"test:pr": "nx affected --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build",
"test:ci": "nx run-many --targets=test:sherif,test:knip,test:docs,test:eslint,test:lib,test:types,test:build,build",
"test:eslint": "nx affected --target=test:eslint",
- "test:sherif": "sherif",
+ "test:sherif": "sherif --ignore-dependency solid-js --ignore-dependency vite-plugin-solid",
"test:lib": "nx affected --target=test:lib --exclude=examples/**",
"test:lib:dev": "pnpm run test:lib && nx watch --all -- pnpm run test:lib",
"test:build": "nx affected --target=test:build --exclude=examples/**",
@@ -44,7 +44,6 @@
"@changesets/changelog-github": "^0.7.0",
"@changesets/cli": "^2.29.8",
"@eslint-react/eslint-plugin": "^1.53.1",
- "@solidjs/testing-library": "^0.8.10",
"@tanstack/eslint-config": "0.3.2",
"@tanstack/typedoc-config": "0.3.1",
"@tanstack/vite-config": "0.4.1",
diff --git a/packages/solid-form-devtools/package.json b/packages/solid-form-devtools/package.json
index 0994030d3..4e3bf6c1a 100644
--- a/packages/solid-form-devtools/package.json
+++ b/packages/solid-form-devtools/package.json
@@ -58,6 +58,7 @@
"@tanstack/form-devtools": "workspace:*"
},
"devDependencies": {
+ "solid-js": "^1.9.9",
"vite-plugin-solid": "^2.11.8"
}
}
diff --git a/packages/solid-form/package.json b/packages/solid-form/package.json
index 253789745..636db7e00 100644
--- a/packages/solid-form/package.json
+++ b/packages/solid-form/package.json
@@ -31,21 +31,21 @@
},
"type": "module",
"types": "dist/esm/index.d.ts",
- "main": "dist/cjs/index.cjs",
- "module": "dist/esm/index.js",
+ "main": "dist/cjs/packages/solid-form/src/index.cjs",
+ "module": "dist/esm/packages/solid-form/src/index.js",
"exports": {
".": {
"solid": {
- "types": "./dist/source/index.d.ts",
- "default": "./dist/source/index.jsx"
+ "types": "./dist/source/solid-form/src/index.d.ts",
+ "default": "./dist/source/solid-form/src/index.jsx"
},
"import": {
"types": "./dist/esm/index.d.ts",
- "default": "./dist/esm/index.js"
+ "default": "./dist/esm/packages/solid-form/src/index.js"
},
"require": {
"types": "./dist/cjs/index.d.cts",
- "default": "./dist/cjs/index.cjs"
+ "default": "./dist/cjs/packages/solid-form/src/index.cjs"
}
},
"./package.json": "./package.json"
@@ -57,14 +57,16 @@
],
"dependencies": {
"@tanstack/form-core": "workspace:*",
- "@tanstack/solid-store": "^0.11.0"
+ "@tanstack/solid-store": "^0.9.1"
},
"devDependencies": {
- "solid-js": "^1.9.9",
+ "@solidjs/testing-library": "1.0.0-beta.2",
+ "@solidjs/web": "2.0.0-beta.15",
+ "solid-js": "2.0.0-beta.15",
"vite": "^7.2.2",
- "vite-plugin-solid": "^2.11.8"
+ "vite-plugin-solid": "3.0.0-next.5"
},
"peerDependencies": {
- "solid-js": ">=1.9.9"
+ "solid-js": ">=2.0.0-beta.15 <2.0.0-experimental.0"
}
}
diff --git a/packages/solid-form/src/createField.tsx b/packages/solid-form/src/createField.tsx
index 373146864..f7f397c62 100644
--- a/packages/solid-form/src/createField.tsx
+++ b/packages/solid-form/src/createField.tsx
@@ -1,10 +1,10 @@
import { FieldApi } from '@tanstack/form-core'
import {
createComponent,
- createComputed,
- createSignal,
- onCleanup,
- onMount,
+ createMemo,
+ createRenderEffect,
+ omit,
+ onSettled,
} from 'solid-js'
import { useStore } from '@tanstack/solid-store'
import type {
@@ -15,9 +15,11 @@ import type {
FieldValidators,
FormAsyncValidateOrFn,
FormValidateOrFn,
+ Narrow,
} from '@tanstack/form-core'
-import type { Accessor, JSX, JSXElement } from 'solid-js'
+import type { Accessor } from 'solid-js'
+import type { JSX } from '@solidjs/web'
import type {
CreateFieldOptions,
CreateFieldOptionsBound,
@@ -54,6 +56,94 @@ interface SolidFieldApi<
>
}
+export type CreateField<
+ TParentData,
+ TFormOnMount extends undefined | FormValidateOrFn,
+ TFormOnChange extends undefined | FormValidateOrFn,
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnBlur extends undefined | FormValidateOrFn,
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnSubmit extends undefined | FormValidateOrFn,
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnDynamic extends undefined | FormValidateOrFn,
+ TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn,
+ TFormOnServer extends undefined | FormAsyncValidateOrFn,
+ TParentSubmitMeta,
+> = <
+ TName extends DeepKeys,
+ TData extends DeepValue,
+ TOnMount extends undefined | FieldValidateOrFn,
+ TOnChange extends undefined | FieldValidateOrFn,
+ TOnChangeAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnBlur extends undefined | FieldValidateOrFn,
+ TOnBlurAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnSubmit extends undefined | FieldValidateOrFn,
+ TOnSubmitAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+ TOnDynamic extends undefined | FieldValidateOrFn,
+ TOnDynamicAsync extends
+ | undefined
+ | FieldAsyncValidateOrFn,
+>(
+ opts: () => { name: Narrow } & CreateFieldOptionsBound<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync
+ >,
+) => () => FieldApi<
+ TParentData,
+ TName,
+ TData,
+ TOnMount,
+ TOnChange,
+ TOnChangeAsync,
+ TOnBlur,
+ TOnBlurAsync,
+ TOnSubmit,
+ TOnSubmitAsync,
+ TOnDynamic,
+ TOnDynamicAsync,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TParentSubmitMeta
+> &
+ SolidFieldApi<
+ TParentData,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TParentSubmitMeta
+ >
+
// ugly way to trick solid into triggering updates for changes on the fieldApi
function makeFieldReactive<
TParentData,
@@ -167,11 +257,10 @@ function makeFieldReactive<
TFormOnServer,
TParentSubmitMeta
> {
- const [field, setField] = createSignal(fieldApi, { equals: false })
// Subscribe to the pieces of state that should trigger a re-render of the
- // field. For array mode, we only track the length of the array value to
- // avoid re-renders when child properties change. Meta is tracked piece by
- // piece so that consumers re-render when any meta property updates.
+ // field. For array mode, we only track the array version to avoid re-renders
+ // when child properties change. Meta is tracked piece by piece so that
+ // consumers re-render when any meta property updates.
// See: https://github.com/TanStack/form/issues/1961
const reactiveStateValue = useStore(fieldApi.store, (state) =>
mode === 'array' ? state.meta._arrayVersion || 0 : state.value,
@@ -200,19 +289,20 @@ function makeFieldReactive<
fieldApi.store,
(state) => state.meta.isValidating,
)
- // Run before initial render
- createComputed(() => {
- // Read all reactive sources to track them as dependencies
- reactiveStateValue()
- reactiveMetaIsTouched()
- reactiveMetaIsBlurred()
- reactiveMetaIsDirty()
- reactiveMetaErrorMap()
- reactiveMetaErrorSourceMap()
- reactiveMetaIsValidating()
- setField(fieldApi)
- })
- return field
+ return createMemo(
+ () => {
+ // Read all reactive sources to track them as dependencies
+ reactiveStateValue()
+ reactiveMetaIsTouched()
+ reactiveMetaIsBlurred()
+ reactiveMetaIsDirty()
+ reactiveMetaErrorMap()
+ reactiveMetaErrorSourceMap()
+ reactiveMetaIsValidating()
+ return fieldApi
+ },
+ { equals: false },
+ )
}
export function createField<
@@ -282,25 +372,35 @@ export function createField<
let mounted = false
// Instantiates field meta and removes it when unrendered
- onMount(() => {
+ onSettled(() => {
+ api.update(opts())
const cleanupFn = api.mount()
mounted = true
- onCleanup(() => {
- cleanupFn()
+ return () => {
mounted = false
- })
+ cleanupFn()
+ }
})
/**
* fieldApi.update should not have any side effects. Think of it like a `useRef`
* that we need to keep updated every render with the most up-to-date information.
*
- * createComputed to make sure this effect runs before render effects
+ * createRenderEffect keeps the api options in sync before user effects run.
*/
- createComputed(() => {
- if (!mounted) return
- api.update(opts())
- })
+ createRenderEffect(
+ () => {
+ const nextOptions = opts()
+ return mounted ? nextOptions : undefined
+ },
+ (options) => {
+ if (options) {
+ api.update(options)
+ }
+
+ return undefined
+ },
+ )
return makeFieldReactive<
TParentData,
@@ -566,7 +666,7 @@ interface FieldComponentProps<
TFormOnServer,
TParentSubmitMeta
>,
- ) => JSXElement
+ ) => JSX.Element
}
/**
@@ -741,8 +841,7 @@ export function Field<
TFormOnServer,
TParentSubmitMeta
>(() => {
- const { children, ...fieldOptions } = props
- return fieldOptions
+ return omit(props, 'children')
})
return <>{createComponent(() => props.children(fieldApi), {})}>
diff --git a/packages/solid-form/src/createFieldGroup.tsx b/packages/solid-form/src/createFieldGroup.tsx
index 0310dd9d9..de9cd4d84 100644
--- a/packages/solid-form/src/createFieldGroup.tsx
+++ b/packages/solid-form/src/createFieldGroup.tsx
@@ -1,7 +1,8 @@
import { FieldGroupApi, functionalUpdate } from '@tanstack/form-core'
import { useStore } from '@tanstack/solid-store'
-import { onCleanup, onMount } from 'solid-js'
-import type { Component, JSX, ParentProps } from 'solid-js'
+import { onSettled } from 'solid-js'
+import type { Component, ParentProps } from 'solid-js'
+import type { JSX } from '@solidjs/web'
import type {
DeepKeysOfType,
FieldGroupState,
@@ -193,27 +194,28 @@ export function createFieldGroup<
TFormComponents
> = api as never
- extendedApi.AppForm = (appFormProps) =>
- extendedApi.AppField = (props) => (
-
+ extendedApi.AppForm = (appFormProps: any) => (
+
)
- extendedApi.Field = (props) => (
-
- )
- extendedApi.Subscribe = (props) => {
+ extendedApi.AppField = (props: any) => {
+ const fieldOptions = () => api.getFormFieldOptions(props)
+ return
+ }
+ extendedApi.Field = (props: any) => {
+ const fieldOptions = () => api.getFormFieldOptions(props)
+ return
+ }
+ extendedApi.Subscribe = (props: any) => {
const data = useStore(api.store, props.selector)
return functionalUpdate(props.children, data()) as Element
}
- let mounted = false
- onMount(() => {
+ onSettled(() => {
const cleanupFn = api.mount()
- mounted = true
- onCleanup(() => {
+ return () => {
cleanupFn()
- mounted = false
- })
+ }
})
return Object.assign(extendedApi, {
diff --git a/packages/solid-form/src/createForm.tsx b/packages/solid-form/src/createForm.tsx
index 844dfa833..e7bf5ad7f 100644
--- a/packages/solid-form/src/createForm.tsx
+++ b/packages/solid-form/src/createForm.tsx
@@ -1,5 +1,5 @@
import { FormApi, functionalUpdate } from '@tanstack/form-core'
-import { createComputed, onMount } from 'solid-js'
+import { createRenderEffect, onSettled } from 'solid-js'
import { useStore } from '@tanstack/solid-store'
import { Field, createField } from './createField'
import { FormGroup } from './createFormGroup'
@@ -9,8 +9,8 @@ import type {
FormState,
FormValidateOrFn,
} from '@tanstack/form-core'
-import type { JSXElement } from 'solid-js'
-import type { FieldComponent } from './createField'
+import type { JSX } from '@solidjs/web'
+import type { CreateField, FieldComponent } from './createField'
import type { FormGroupComponent } from './createFormGroup'
export interface SolidFormApi<
@@ -41,6 +41,20 @@ export interface SolidFormApi<
TFormOnServer,
TSubmitMeta
>
+ createField: CreateField<
+ TParentData,
+ TFormOnMount,
+ TFormOnChange,
+ TFormOnChangeAsync,
+ TFormOnBlur,
+ TFormOnBlurAsync,
+ TFormOnSubmit,
+ TFormOnSubmitAsync,
+ TFormOnDynamic,
+ TFormOnDynamicAsync,
+ TFormOnServer,
+ TSubmitMeta
+ >
FormGroup: FormGroupComponent<
TParentData,
TFormOnMount,
@@ -124,8 +138,8 @@ export interface SolidFormApi<
>
>,
) => TSelected
- children: ((state: () => NoInfer) => JSXElement) | JSXElement
- }) => JSXElement
+ children: ((state: () => NoInfer) => JSX.Element) | JSX.Element
+ }) => JSX.Element
}
/**
@@ -232,19 +246,29 @@ export function createForm<
TSubmitMeta
> = api as never
- extendedApi.Field = (props) =>
- extendedApi.FormGroup = (props) =>
- extendedApi.useStore = (selector) => useStore(api.store, selector)
- extendedApi.Subscribe = (props) =>
+ extendedApi.Field = (props: any) =>
+ extendedApi.createField = (props: any) =>
+ createField(() => {
+ return { ...props(), form: api }
+ }) as never
+ extendedApi.FormGroup = (props: any) =>
+ extendedApi.useStore = (selector: any) => useStore(api.store, selector)
+ extendedApi.Subscribe = (props: any) =>
functionalUpdate(props.children, useStore(api.store, props.selector))
- onMount(api.mount)
+ onSettled(api.mount)
/**
* formApi.update should not have any side effects. Think of it like a `useRef`
* that we need to keep updated every render with the most up-to-date information.
*/
- createComputed(() => api.update(opts?.()))
+ createRenderEffect(
+ () => opts?.(),
+ (options) => {
+ api.update(options)
+ return undefined
+ },
+ )
return extendedApi
}
diff --git a/packages/solid-form/src/createFormGroup.tsx b/packages/solid-form/src/createFormGroup.tsx
index 47467a88a..ba7f77c20 100644
--- a/packages/solid-form/src/createFormGroup.tsx
+++ b/packages/solid-form/src/createFormGroup.tsx
@@ -1,10 +1,9 @@
import { FormGroupApi, functionalUpdate } from '@tanstack/form-core'
import {
createComponent,
- createComputed,
- createSignal,
- onCleanup,
- onMount,
+ createMemo,
+ createRenderEffect,
+ onSettled,
} from 'solid-js'
import { useStore } from '@tanstack/solid-store'
import type {
@@ -17,7 +16,8 @@ import type {
FormGroupValidateOrFn,
FormValidateOrFn,
} from '@tanstack/form-core'
-import type { Accessor, JSX, JSXElement } from 'solid-js'
+import type { Accessor } from 'solid-js'
+import type { JSX } from '@solidjs/web'
// ugly way to trick solid into triggering updates for changes on the formGroupApi
function makeFormGroupReactive<
@@ -112,16 +112,16 @@ function makeFormGroupReactive<
TFormOnServer,
TParentSubmitMeta
> {
- const [group, setGroup] = createSignal(formGroupApi, { equals: false })
// Handle shallow comparison to make sure that Derived doesn't create a new setGroup call every time
const store = useStore(formGroupApi.store, (store) => store)
- // Run before initial render
- createComputed(() => {
- // Use the store to track dependencies
- store()
- setGroup(formGroupApi)
- })
- return group
+ return createMemo(
+ () => {
+ // Use the store to track dependencies
+ store()
+ return formGroupApi
+ },
+ { equals: false },
+ )
}
export function createFormGroup<
@@ -197,25 +197,29 @@ export function createFormGroup<
let mounted = false
// Instantiates form group meta and removes it when unrendered
- onMount(() => {
+ onSettled(() => {
const cleanupFn = api.mount()
mounted = true
- onCleanup(() => {
+ return () => {
cleanupFn()
mounted = false
- })
+ }
})
/**
* formGroupApi.update should not have any side effects. Think of it like a `useRef`
* that we need to keep updated every render with the most up-to-date information.
*
- * createComputed to make sure this effect runs before render effects
+ * createRenderEffect to make sure this effect runs before render effects
*/
- createComputed(() => {
- if (!mounted) return
- api.update(opts())
- })
+ createRenderEffect(
+ () => opts(),
+ (options) => {
+ if (!mounted) return undefined
+ api.update(options)
+ return undefined
+ },
+ )
return makeFormGroupReactive<
TParentData,
@@ -424,7 +428,7 @@ export type FormGroupComponent<
TParentSubmitMeta,
ExtendedApi
>,
-) => JSXElement
+) => JSX.Element
interface FormGroupComponentProps<
TParentData,
@@ -518,7 +522,7 @@ interface FormGroupComponentProps<
TFormOnServer,
TParentSubmitMeta
>,
- ) => JSXElement
+ ) => JSX.Element
}
export function FormGroup<
diff --git a/packages/solid-form/src/createFormHook.tsx b/packages/solid-form/src/createFormHook.tsx
index a86afab24..ad6a68e71 100644
--- a/packages/solid-form/src/createFormHook.tsx
+++ b/packages/solid-form/src/createFormHook.tsx
@@ -1,8 +1,8 @@
import {
createComponent,
createContext,
- mergeProps,
- splitProps,
+ merge,
+ omit,
useContext,
} from 'solid-js'
import { createFieldGroup } from './createFieldGroup'
@@ -18,13 +18,8 @@ import type {
FormOptions,
FormValidateOrFn,
} from '@tanstack/form-core'
-import type {
- Accessor,
- Component,
- Context,
- JSXElement,
- ParentProps,
-} from 'solid-js'
+import type { Accessor, Component, Context, ParentProps } from 'solid-js'
+import type { JSX } from '@solidjs/web'
import type { FieldComponent } from './createField'
import type { AppFieldExtendedSolidFieldGroupApi } from './createFieldGroup'
import type { SolidFormExtendedApi } from './createForm'
@@ -257,7 +252,7 @@ export interface WithFormProps<
>
}
>,
- ) => JSXElement
+ ) => JSX.Element
}
export interface WithFieldGroupProps<
@@ -294,7 +289,7 @@ export interface WithFieldGroupProps<
>
}
>,
- ) => JSXElement
+ ) => JSX.Element
}
export function createFormHook<
@@ -351,26 +346,18 @@ export function createFormHook<
const AppForm = ((formProps) => {
return (
-
- {formProps.children}
-
+ {formProps.children}
)
}) as Component
const AppField = ((_props) => {
- const [childProps, fieldProps] = splitProps(_props, ['children'])
+ const fieldProps = omit(_props, 'children')
return (
- {(field) => (
-
- {createComponent(
- () =>
- childProps.children(
- Object.assign(field, opts.fieldComponents),
- ),
- {},
- )}
-
+ {(field: any) => (
+
+ {_props.children(Object.assign(field, opts.fieldComponents))}
+
)}
)
@@ -472,7 +459,7 @@ export function createFormHook<
return (innerProps) =>
createComponent(
render as Component,
- mergeProps(props ?? {}, innerProps),
+ props ? merge(props, innerProps) : innerProps,
)
}
@@ -549,7 +536,7 @@ export function createFormHook<
fields: TFields
}
>,
- ) => JSXElement {
+ ) => JSX.Element {
return function Render(innerProps) {
const fieldGroupProps = {
form: innerProps.form,
@@ -560,7 +547,7 @@ export function createFormHook<
const fieldGroupApi = createFieldGroup(() => fieldGroupProps)
return createComponent(
render as Component,
- mergeProps(props ?? {}, innerProps, { group: fieldGroupApi as any }),
+ merge(props ?? {}, innerProps, { group: fieldGroupApi as any }),
)
}
}
diff --git a/packages/solid-form/tests/createField.test.tsx b/packages/solid-form/tests/createField.test.tsx
index 00395ee31..d68ce16f1 100644
--- a/packages/solid-form/tests/createField.test.tsx
+++ b/packages/solid-form/tests/createField.test.tsx
@@ -1,7 +1,7 @@
import { describe, expect, it, vi } from 'vitest'
import { render, waitFor } from '@solidjs/testing-library'
import { userEvent } from '@testing-library/user-event'
-import { Index, Show } from 'solid-js'
+import { Repeat, Show } from 'solid-js'
import { createForm } from '../src/index'
import { sleep } from './utils'
@@ -402,8 +402,8 @@ describe('createField', () => {
0}>
{/* Do not change this to For or the test will fail */}
-
- {(_, i) => {
+
+ {(i) => {
return (
{(subField) => (
@@ -430,7 +430,7 @@ describe('createField', () => {
)
}}
-
+