Skip to content

WIP: feat(solid-form): support Solid 2 beta#2122

Open
brenelz wants to merge 5 commits into
TanStack:mainfrom
brenelz:solid-v2-beta
Open

WIP: feat(solid-form): support Solid 2 beta#2122
brenelz wants to merge 5 commits into
TanStack:mainfrom
brenelz:solid-v2-beta

Conversation

@brenelz

@brenelz brenelz commented Apr 11, 2026

Copy link
Copy Markdown

Update the package runtime, tests, and Vite test setup for the Solid 2 beta API surface so solid-form can build and test against beta 6.

Summary by CodeRabbit

  • Dependencies

    • Updated Solid.js to 2.0.0-beta.15 with adjusted peer dependency constraints
    • Upgraded vite-plugin-solid to 3.0.0-next.5
    • Added @solidjs/web 2.0.0-beta.615and testing library support
  • Improvements

    • Refactored internal form field and lifecycle handling for better compatibility with Solid.js 2.0
    • Enhanced testing infrastructure

Update the package runtime, tests, and Vite test setup for the Solid 2 beta API surface so solid-form can build and test against beta 6.
@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fe003dfe-d9c3-47c9-b525-d9cbebe11b19

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR updates the solid-form package to SolidJS 2.0.0-beta.6, refactoring lifecycle management from onMount/createComputed to onSettled/createRenderEffect patterns, replacing prop utilities with merge/omit, adding a custom testing-library implementation, and updating tests to use Repeat instead of Index for array rendering.

Changes

Cohort / File(s) Summary
Package Dependencies
packages/solid-form/package.json
Bumped solid-js to fixed 2.0.0-beta.6, updated peer dependency constraint to >=2.0.0-beta.6 <2.0.0-experimental.0, added @solidjs/web@2.0.0-beta.6 and @testing-library/dom^10.4.0 to devDependencies, upgraded vite-plugin-solid to fixed 3.0.0-next.4.
Lifecycle Refactoring
packages/solid-form/src/createForm.tsx, packages/solid-form/src/createField.tsx, packages/solid-form/src/createFieldGroup.tsx
Replaced onMount/onCleanup with onSettled, replaced createComputed with createRenderEffect for reactive effect handling. In createFieldGroup, refactored AppField and Field components to use function-based field option closures.
Prop Composition Refactoring
packages/solid-form/src/createFormHook.tsx
Replaced Solid mergeProps/splitProps with merge/omit utilities, simplified conditional merge logic in withForm and withFieldGroup, refactored AppField to inline children invocation.
Testing Infrastructure
packages/solid-form/tests/testing-library.ts, packages/solid-form/vite.config.ts
Added new custom testing-library implementation with render and cleanup functions for SolidJS component testing. Updated Vite config to alias @solidjs/testing-library to the new testing-library module.
Test Updates
packages/solid-form/tests/createField.test.tsx, packages/solid-form/tests/createForm.test.tsx, packages/solid-form/tests/createFormHook.test.tsx
Replaced Solid Index control with Repeat for array-mode rendering across multiple test cases; updated createEffect patterns to use explicit dependency/accessor function syntax; adjusted iterator callback signatures accordingly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Lifecycle spins in circles new,
From onMount to onSettled true,
Props merge cleaner, tests repeat,
SolidJS beta makes the beat!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description clearly summarizes the changes but lacks the required template structure including 'Changes' section, Checklist, and 'Release Impact' details needed for proper PR documentation. Add the full PR template with explicit 'Changes' details explaining the API migration, confirm checklist items completion, and clarify whether a changeset is needed for this feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: updating solid-form to support Solid 2 beta.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloud Bot commented Apr 11, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 1db6f68

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ❌ Failed 3m 52s View ↗
nx run-many --target=build --exclude=examples/** ✅ Succeeded 38s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-27 01:03:46 UTC

@pkg-pr-new

pkg-pr-new Bot commented Apr 11, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-form

npm i https://pkg.pr.new/@tanstack/angular-form@2122

@tanstack/form-core

npm i https://pkg.pr.new/@tanstack/form-core@2122

@tanstack/form-devtools

npm i https://pkg.pr.new/@tanstack/form-devtools@2122

@tanstack/lit-form

npm i https://pkg.pr.new/@tanstack/lit-form@2122

@tanstack/preact-form

npm i https://pkg.pr.new/@tanstack/preact-form@2122

@tanstack/react-form

npm i https://pkg.pr.new/@tanstack/react-form@2122

@tanstack/react-form-devtools

npm i https://pkg.pr.new/@tanstack/react-form-devtools@2122

@tanstack/react-form-nextjs

npm i https://pkg.pr.new/@tanstack/react-form-nextjs@2122

@tanstack/react-form-remix

npm i https://pkg.pr.new/@tanstack/react-form-remix@2122

@tanstack/react-form-start

npm i https://pkg.pr.new/@tanstack/react-form-start@2122

@tanstack/solid-form

npm i https://pkg.pr.new/@tanstack/solid-form@2122

@tanstack/solid-form-devtools

npm i https://pkg.pr.new/@tanstack/solid-form-devtools@2122

@tanstack/svelte-form

npm i https://pkg.pr.new/@tanstack/svelte-form@2122

@tanstack/vue-form

npm i https://pkg.pr.new/@tanstack/vue-form@2122

commit: 1db6f68

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/solid-form/tests/createField.test.tsx`:
- Line 4: The test imports Repeat from 'solid-js' which doesn't exist in Solid
2.0; remove the Repeat import and replace any usage of Repeat with For
keyed={false} from 'solid-js' (keep Show import as-is), adapting the render
callback to the For signature (item, i) => ... where item and i are accessors;
if you actually need an index-only Repeat component, import it from
`@solid-primitives/range` instead.

In `@packages/solid-form/tests/testing-library.ts`:
- Around line 23-25: The container selection logic currently can remove
caller-provided containers and fails to clean up auto-created containers under a
custom baseElement, and returning raw dispose prevents deregistering on manual
unmount; fix by introducing an ownedContainer boolean (set true when you create
the div for container) next to baseElement/container logic, wrap the returned
dispose in a custom unmount function that (1) calls the original dispose, (2) if
ownedContainer is true removes the container from the DOM, and (3) removes the
entry from your internal registry so cleanup() only iterates and removes
containers that were created (owned) by this module; update cleanup() to check
ownedContainer/registry flags before removing nodes and ensure all places return
the custom unmount instead of the raw dispose.

In `@packages/solid-form/vite.config.ts`:
- Line 3: ESLint flagged the import order: move the "fileURLToPath" import from
node:url so it appears before the vitest/config import; update the top of
vite.config.ts to import { fileURLToPath } from 'node:url' prior to any import
from 'vitest/config' (so adjust the sequence around the existing import lines in
this file).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6909c33b-d852-4dc9-a4b4-d20422c73d6a

📥 Commits

Reviewing files that changed from the base of the PR and between 254f157 and 977f613.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • packages/solid-form/package.json
  • packages/solid-form/src/createField.tsx
  • packages/solid-form/src/createFieldGroup.tsx
  • packages/solid-form/src/createForm.tsx
  • packages/solid-form/src/createFormHook.tsx
  • packages/solid-form/tests/createField.test.tsx
  • packages/solid-form/tests/createForm.test.tsx
  • packages/solid-form/tests/createFormHook.test.tsx
  • packages/solid-form/tests/testing-library.ts
  • packages/solid-form/vite.config.ts

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'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

SolidJS 2.0 Repeat component API signature

💡 Result:

SolidJS 2.0 does not have a built-in "Repeat" component in core. Core control flow components are , , /, (replaces Suspense), and (replaces ErrorBoundary). In SolidJS 2.0 beta: - from 1.x is replaced by - children now receive accessors: (item, i) => ... where item and i are called. A component exists in the third-party @solid-primitives/range package (updated Feb 2026), with API: function Repeat<T>(props: { times: number; fallback?: T; children: ((index: number) => T) | T; }): Accessor<T[]>; Example: <Repeat times={10}> <div></div> </Repeat> or with render prop: <Repeat times={10}> {index => <div>{index}</div>} </Repeat> No evidence of core Repeat in 2.0 docs/RFCs/release notes. Official 2.0 docs at docs.solidjs.com cover 1.x; 2.0 migration in GitHub next branch.

Citations:


Repeat is not exported from solid-js 2.0 — use <For keyed={false}> instead.

Repeat does not exist in SolidJS 2.0 core. The import at line 4 will fail. The correct migration from Index is <For keyed={false}>, which receives the signature (item, i) => ... where both are accessor functions. If a Repeat component is needed for index-only iteration, it exists as a third-party component in @solid-primitives/range (not in core solid-js).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/solid-form/tests/createField.test.tsx` at line 4, The test imports
Repeat from 'solid-js' which doesn't exist in Solid 2.0; remove the Repeat
import and replace any usage of Repeat with For keyed={false} from 'solid-js'
(keep Show import as-is), adapting the render callback to the For signature
(item, i) => ... where item and i are accessors; if you actually need an
index-only Repeat component, import it from `@solid-primitives/range` instead.

Comment on lines +23 to +25
const baseElement = options.baseElement ?? document.body
const container =
options.container ?? baseElement.appendChild(document.createElement('div'))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n packages/solid-form/tests/testing-library.ts

Repository: TanStack/form

Length of output: 2198


Track container ownership and deregister on unmount to prevent cleanup bugs.

Current implementation has three reliability problems:

  • Line 60 can remove caller-provided containers. The parentNode check doesn't distinguish between auto-created and caller-managed containers.
  • Auto-created containers under custom baseElement are not cleaned up (parentNode won't equal document.body).
  • Line 51 returns raw dispose, so manual unmount() calls don't remove the registry entry, risking stale references and double disposal when cleanup() runs.

Add ownedContainer boolean to track ownership, wrap cleanup logic in a custom unmount function, and update cleanup() to only remove containers this module created:

🔧 Proposed fix
 type RenderRef = {
   container: HTMLElement
   dispose: () => void
+  ownedContainer: boolean
 }
@@
 export function render(
@@
 ) {
   const baseElement = options.baseElement ?? document.body
-  const container =
-    options.container ?? baseElement.appendChild(document.createElement('div'))
+  const ownedContainer = !options.container
+  const container =
+    options.container ?? baseElement.appendChild(document.createElement('div'))
@@
-  mountedContainers.add({ container, dispose })
+  const ref: RenderRef = { container, dispose, ownedContainer }
+  mountedContainers.add(ref)
@@
+  const unmount = () => {
+    ref.dispose()
+    if (ref.ownedContainer && ref.container.parentNode) {
+      ref.container.parentNode.removeChild(ref.container)
+    }
+    mountedContainers.delete(ref)
+  }
+
   return {
@@
-    unmount: dispose,
+    unmount,
     ...queryHelpers,
   }
 }
@@
 export function cleanup() {
   for (const ref of Array.from(mountedContainers)) {
     ref.dispose()
 
-    if (ref.container.parentNode === document.body) {
-      document.body.removeChild(ref.container)
+    if (ref.ownedContainer && ref.container.parentNode) {
+      ref.container.parentNode.removeChild(ref.container)
     }
 
     mountedContainers.delete(ref)
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const baseElement = options.baseElement ?? document.body
const container =
options.container ?? baseElement.appendChild(document.createElement('div'))
type RenderRef = {
container: HTMLElement
dispose: () => void
ownedContainer: boolean
}
export function render(
Component: ParentComponent,
options: RenderOptions = {},
) {
const baseElement = options.baseElement ?? document.body
const ownedContainer = !options.container
const container =
options.container ?? baseElement.appendChild(document.createElement('div'))
// ... component mounting code ...
const ref: RenderRef = { container, dispose, ownedContainer }
mountedContainers.add(ref)
const unmount = () => {
ref.dispose()
if (ref.ownedContainer && ref.container.parentNode) {
ref.container.parentNode.removeChild(ref.container)
}
mountedContainers.delete(ref)
}
return {
container,
unmount,
...queryHelpers,
}
}
export function cleanup() {
for (const ref of Array.from(mountedContainers)) {
ref.dispose()
if (ref.ownedContainer && ref.container.parentNode) {
ref.container.parentNode.removeChild(ref.container)
}
mountedContainers.delete(ref)
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/solid-form/tests/testing-library.ts` around lines 23 - 25, The
container selection logic currently can remove caller-provided containers and
fails to clean up auto-created containers under a custom baseElement, and
returning raw dispose prevents deregistering on manual unmount; fix by
introducing an ownedContainer boolean (set true when you create the div for
container) next to baseElement/container logic, wrap the returned dispose in a
custom unmount function that (1) calls the original dispose, (2) if
ownedContainer is true removes the container from the DOM, and (3) removes the
entry from your internal registry so cleanup() only iterates and removes
containers that were created (owned) by this module; update cleanup() to check
ownedContainer/registry flags before removing nodes and ensure all places return
the custom unmount instead of the raw dispose.

Comment thread packages/solid-form/vite.config.ts Outdated
@@ -1,10 +1,20 @@
import { defineConfig, mergeConfig } from 'vitest/config'
import { tanstackViteConfig } from '@tanstack/vite-config'
import { fileURLToPath } from 'node:url'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Import order issue flagged by ESLint.

The node:url import should be placed before vitest/config to follow the project's import ordering conventions.

🔧 Suggested fix
+import { fileURLToPath } from 'node:url'
 import { defineConfig, mergeConfig } from 'vitest/config'
 import { tanstackViteConfig } from '@tanstack/vite-config'
-import { fileURLToPath } from 'node:url'
 import solid from 'vite-plugin-solid'
🧰 Tools
🪛 ESLint

[error] 3-3: node:url import should occur before import of vitest/config

(import/order)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/solid-form/vite.config.ts` at line 3, ESLint flagged the import
order: move the "fileURLToPath" import from node:url so it appears before the
vitest/config import; update the top of vite.config.ts to import { fileURLToPath
} from 'node:url' prior to any import from 'vitest/config' (so adjust the
sequence around the existing import lines in this file).

@brenelz brenelz marked this pull request as draft April 11, 2026 22:34
Update solid-form packaging, supporting examples, and Solid package manifests so the Solid 2 beta toolchain resolves consistently across the workspace.
@brenelz brenelz changed the title WIP: feat(solid-form): support Solid 2 beta 6 WIP: feat(solid-form): support Solid 2 beta Jun 27, 2026
brenelz and others added 2 commits June 26, 2026 19:22
- Merge origin/main, bringing in FormGroup and the TanStack#1961 field-reactivity
  fix, adapted to Solid 2 beta primitives (createMemo/createRenderEffect/
  onSettled instead of the removed createComputed/onMount).
- Bump solid-js and @solidjs/web to 2.0.0-beta.15 across solid-form and
  the solid examples.
- Migrate JSX types for beta.15: JSX moved out of solid-js core to
  @solidjs/web (jsxImportSource + type imports); JSXElement -> JSX.Element;
  createMemo now takes (compute, options).
- Pin @tanstack/solid-store to ^0.9.1 (0.11.0 imports solid-js/web, which
  no longer exists in Solid 2).
- Keep solid-form-devtools on Solid v1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@socket-security

socket-security Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​tanstack/​solid-store@​0.11.0 ⏵ 0.9.39710066 -391100
Added@​tanstack/​solid-devtools@​0.8.8771008597100
Added@​solidjs/​web@​2.0.0-beta.15791008296100
Addedvite-plugin-solid@​3.0.0-next.59910010088100
Added@​solidjs/​testing-library@​1.0.0-beta.29910010091100
Addedsolid-js@​2.0.0-beta.151001009595100

View full report

@socket-security

socket-security Bot commented Jun 27, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn Medium
Low adoption: npm @solidjs/signals

Location: Package overview

From: pnpm-lock.yamlnpm/solid-js@2.0.0-beta.15npm/@solidjs/signals@2.0.0-beta.15

ℹ Read more on: This package | This alert | What are unpopular packages?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Unpopular packages may have less maintenance and contain other problems.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@solidjs/signals@2.0.0-beta.15. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Low adoption: npm @solidjs/web

Location: Package overview

From: examples/solid/array/package.jsonnpm/@solidjs/web@2.0.0-beta.15

ℹ Read more on: This package | This alert | What are unpopular packages?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Unpopular packages may have less maintenance and contain other problems.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@solidjs/web@2.0.0-beta.15. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@brenelz brenelz marked this pull request as ready for review June 27, 2026 00:36
…mple beta migration

- solid-form: use @solidjs/testing-library@1.0.0-beta.2 (Solid 2 support)
  instead of the local testing-library shim; drop the now-unused vite alias
  and @testing-library/dom devDep.
- Keep the Solid-based devtools chain (@tanstack/devtools, @tanstack/devtools-ui)
  on Solid v1 via a packageExtensions pin on @tanstack/react-devtools — these
  import `solid-js/web`, which no longer exists in Solid 2, so bundling them
  in (e.g. React) examples broke against the beta hoisted for solid-form.
- sherif: ignore the intentional solid-js / vite-plugin-solid version splits
  (Solid v1 devtools vs Solid 2 beta solid-form/examples) and remove the dead
  root @solidjs/testing-library devDep.
- Migrate the remaining solid examples to Solid 2 beta.15: jsxImportSource ->
  @solidjs/web for the beta examples, and bring multi-step-wizard onto beta
  (solid-js, @solidjs/web, vite-plugin-solid, and `solid-js/web` -> @solidjs/web).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant