---
title: Forms
subtitle: A guide to building forms with Base UI components.
description: A guide to building forms with Base UI components.
---

> FineSoft Components documentation. Independent Stencil port; not the official Base UI website.
>
> React API text and `@base-ui/react` examples are upstream references. FineSoft Stencil examples use `finesoft-components`. Do not treat the two packages as interchangeable.

# Forms

A guide to building forms with Base UI components.

Base UI form control components extend the native [constraint validation API](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api) so you can build forms for collecting user input or providing control over an interface. They also integrate seamlessly with third-party libraries like [React Hook Form](/react/handbook/forms.md) and [TanStack Form](/react/handbook/forms.md).

## Demo

### Component theme

The Stencil example uses the built-in component theme. The frozen React comparison retains its original Tailwind styling.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactExample from './react-hero';
import StencilExample from './docs-themed-preview';
import { formHTML, configureForm } from './stencil-form';

export default function Comparison() {
  const options = { themed: true };
  return (
    <StencilComparison
      component="handbook-form-hero"
      react={<ReactExample />}
      stencil={null}
      renderSource={() => formHTML(options)}
      beforeHydrate={document => configureForm(document, options)}
      clientStencil={<StencilExample />}
    />
  );
}
```

```tsx
/* react-hero.tsx */
'use client';
import * as React from 'react';
import { Button } from './button';
import { CheckboxGroup } from './checkbox-group';
import { Form } from './form';
import { RadioGroup } from './radio-group';
import { ToastProvider, useToastManager } from './toast';
import * as Autocomplete from './autocomplete';
import * as Checkbox from './checkbox';
import * as Combobox from './combobox';
import * as Field from './field';
import * as Fieldset from './fieldset';
import * as NumberField from './number-field';
import * as Radio from './radio';
import * as Select from './select';
import * as Slider from './slider';
import * as Switch from './switch';

function ExampleForm() {
  const toastManager = useToastManager();
  return (
    <Form
      aria-label="Launch new cloud server"
      onFormSubmit={formValues => {
        toastManager.add({
          title: 'Form submitted',
          description: 'The form contains these values:',
          data: formValues,
        });
      }}
    >
      <Field.Root name="serverName">
        <Field.Label>Server name</Field.Label>
        <Field.Control defaultValue="" placeholder="e.g. api-server-01" required minLength={3} pattern=".*[A-Za-z].*" />
        <Field.Description>Must be 3 or more characters long</Field.Description>
        <Field.Error />
      </Field.Root>

      <Field.Root name="region">
        <Combobox.Root items={REGIONS} required>
          <div className="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
            <Field.Label className="mb-1 block">Region</Field.Label>
            <Combobox.InputGroup>
              <Combobox.Input placeholder="e.g. eu-central-1" />
              <div className="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
                <Combobox.Clear />
                <Combobox.Trigger>
                  <Combobox.CaretDownIcon />
                </Combobox.Trigger>
              </div>
            </Combobox.InputGroup>
          </div>
          <Combobox.Portal>
            <Combobox.Positioner>
              <Combobox.Popup>
                <Combobox.Empty>No matches</Combobox.Empty>
                <Combobox.List>
                  {(region: string) => {
                    return (
                      <Combobox.Item key={region} value={region}>
                        <Combobox.ItemIndicator>
                          <CheckIcon />
                        </Combobox.ItemIndicator>
                        <span className="col-start-2">{region}</span>
                      </Combobox.Item>
                    );
                  }}
                </Combobox.List>
              </Combobox.Popup>
            </Combobox.Positioner>
          </Combobox.Portal>
        </Combobox.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="containerImage">
        <Autocomplete.Root items={IMAGES} mode="both" itemToStringValue={(itemValue: Image) => itemValue.url} required>
          <Field.Label>Container image</Field.Label>
          <Autocomplete.Input placeholder="e.g. docker.io/library/node:latest" />
          <Field.Description>Enter a registry URL with optional tags</Field.Description>
          <Autocomplete.Portal>
            <Autocomplete.Positioner>
              <Autocomplete.Popup>
                <Autocomplete.List>
                  {(image: Image) => {
                    return (
                      <Autocomplete.Item key={image.url} value={image}>
                        <span>{image.name}</span>
                        <span className="font-mono whitespace-nowrap text-xs opacity-80">{image.url}</span>
                      </Autocomplete.Item>
                    );
                  }}
                </Autocomplete.List>
              </Autocomplete.Popup>
            </Autocomplete.Positioner>
          </Autocomplete.Portal>
        </Autocomplete.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="serverType">
        <Select.Root items={SERVER_TYPES} required>
          <div className="w-fit space-y-1">
            <Select.Label>Server type</Select.Label>
            <Select.Trigger className="w-48">
              <Select.Value />
              <Select.Icon>
                <CaretUpDownIcon />
              </Select.Icon>
            </Select.Trigger>
          </div>
          <Select.Portal>
            <Select.Positioner>
              <Select.Popup>
                <Select.ScrollUpArrow />
                <Select.List>
                  {SERVER_TYPES.map(({ label, value }) => {
                    return (
                      <Select.Item key={value} value={value}>
                        <Select.ItemIndicator>
                          <CheckIcon />
                        </Select.ItemIndicator>
                        <Select.ItemText>{label}</Select.ItemText>
                      </Select.Item>
                    );
                  })}
                </Select.List>
                <Select.ScrollDownArrow />
              </Select.Popup>
            </Select.Positioner>
          </Select.Portal>
        </Select.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="numOfInstances">
        <NumberField.Root defaultValue={undefined} min={1} max={64} required>
          <Field.Label>Number of instances</Field.Label>
          <NumberField.Group>
            <NumberField.Decrement>
              <MinusIcon />
            </NumberField.Decrement>
            <NumberField.Input />
            <NumberField.Increment>
              <PlusIcon />
            </NumberField.Increment>
          </NumberField.Group>
        </NumberField.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="scalingThreshold">
        <Fieldset.Root
          render={
            <Slider.Root
              defaultValue={[0.2, 0.8]}
              thumbAlignment="edge"
              min={0}
              max={1}
              step={0.01}
              format={{
                style: 'percent',
                minimumFractionDigits: 0,
                maximumFractionDigits: 0,
              }}
              className="w-full gap-y-2"
            />
          }
        >
          <Fieldset.Legend>Scaling threshold</Fieldset.Legend>
          <Slider.Value className="col-start-2 text-end" />
          <Slider.Control>
            <Slider.Track>
              <Slider.Indicator />
              <Slider.Thumb index={0} aria-label="Minimum threshold" />
              <Slider.Thumb index={1} aria-label="Maximum threshold" />
            </Slider.Track>
          </Slider.Control>
        </Fieldset.Root>
      </Field.Root>

      <Field.Root name="storageType">
        <Fieldset.Root render={<RadioGroup<'ssd' | 'hdd'> className="gap-4" defaultValue="ssd" />}>
          <Fieldset.Legend className="-mt-px">Storage type</Fieldset.Legend>
          <Field.Item>
            <Field.Label>
              <Radio.Root value="ssd">
                <Radio.Indicator />
              </Radio.Root>
              SSD
            </Field.Label>
          </Field.Item>
          <Field.Item>
            <Field.Label>
              <Radio.Root value="hdd">
                <Radio.Indicator />
              </Radio.Root>
              HDD
            </Field.Label>
          </Field.Item>
        </Fieldset.Root>
      </Field.Root>

      <Field.Root name="restartOnFailure">
        <Field.Label className="gap-2">
          Restart on failure
          <Switch.Root defaultChecked>
            <Switch.Thumb />
          </Switch.Root>
        </Field.Label>
      </Field.Root>

      <Field.Root name="allowedNetworkProtocols">
        <Fieldset.Root render={<CheckboxGroup defaultValue={[]} />}>
          <Fieldset.Legend className="mb-2">Allowed network protocols</Fieldset.Legend>
          <div className="flex gap-4">
            {['http', 'https', 'ssh'].map(val => {
              return (
                <Field.Item key={val}>
                  <Field.Label className="uppercase">
                    <Checkbox.Root value={val}>
                      <Checkbox.Indicator>
                        <CheckIcon />
                      </Checkbox.Indicator>
                    </Checkbox.Root>
                    {val}
                  </Field.Label>
                </Field.Item>
              );
            })}
          </div>
        </Fieldset.Root>
      </Field.Root>

      <Button type="submit" className="mt-3">
        Launch server
      </Button>
    </Form>
  );
}

export default function App() {
  return (
    <ToastProvider>
      <ExampleForm />
    </ToastProvider>
  );
}

function CaretUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="m2.5 8.5 4 4 7-9" />
    </svg>
  );
}

function PlusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13M8 14.5v-13" />
    </svg>
  );
}

function MinusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13" />
    </svg>
  );
}

function cartesian<T extends string[][]>(...arrays: T): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}

const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));

interface Image {
  url: string;
  name: string;
}
/* prettier-ignore */
const IMAGES: Image[] = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map((name) => ({
  url: `docker.io/library/${name}`,
  name,
}));

const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];
```

```tsx
/* docs-themed-preview.tsx */
'use client';
import { NativeStencilPreview } from 'docs/src/components/NativeStencilPreview';
import { mount } from './stencil-themed-hero';
export default function Preview() {
  return <NativeStencilPreview mount={mount} />;
}
```

```ts
/* stencil-form.ts */
import type { Components } from 'finesoft-components';

export interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

export const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};
export const fieldNames = Object.keys(defaultValues) as Array<keyof FormValues>;
export interface FormOptions {
  externalValidation?: boolean;
  nativeForm?: boolean;
  themed?: boolean;
}

function cartesian(...arrays: string[][]): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}
const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));
const IMAGES = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map(name => ({ name, url: `docker.io/library/${name}` }));
const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];

// This same Web Components declaration is used by the browser and by Stencil SSR.
// The framework integrations below only exchange public properties and events.
export function formHTML(options: FormOptions = {}): string {
  if (options.themed) return themedFormHTML(options);
  const { nativeForm = false } = options;
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]" aria-label="Launch new cloud server">
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverName">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Server name</fs-field-label>
      <fs-field-control class="h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Must be 3 or more characters long</fs-field-description>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="region">
      <fs-combobox-root required="">
        <div class="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
          <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white mb-1 block'>Region</fs-field-label>
          <fs-combobox-input-group class="relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>fs-combobox-input>input]:pr-[2.5rem] has-[.combobox-clear]:[&>fs-combobox-input>input]:pr-[calc(0.5rem+2rem*2)]">
            <fs-combobox-input class="h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div class="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
              <fs-combobox-clear class="[&::part(clear)]:box-border [&::part(clear)]:m-0 [&::part(clear)]:p-0 [&::part(clear)]:border-solid [&::part(clear)]:[font-family:inherit] [&::part(clear)]:[font-size:inherit] [&::part(clear)]:[font-weight:inherit] [&::part(clear)]:[line-height:inherit] combobox-clear [&::part(clear)]:flex [&::part(clear)]:h-full [&::part(clear)]:w-6 [&::part(clear)]:items-center [&::part(clear)]:justify-center [&::part(clear)]:border-0 [&::part(clear)]:bg-transparent [&::part(clear)]:p-0 [&::part(clear)]:text-neutral-950 dark:[&::part(clear)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:p-0 [&::part(trigger)]:border-solid [&::part(trigger)]:[font-family:inherit] [&::part(trigger)]:[font-size:inherit] [&::part(trigger)]:[font-weight:inherit] [&::part(trigger)]:[line-height:inherit] [&::part(trigger)]:flex [&::part(trigger)]:h-full [&::part(trigger)]:w-6 [&::part(trigger)]:items-center [&::part(trigger)]:justify-center [&::part(trigger)]:border-0 [&::part(trigger)]:bg-transparent [&::part(trigger)]:p-0 [&::part(trigger)]:text-neutral-950 dark:[&::part(trigger)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner class="outline-none" side-offset="4">
            <fs-combobox-popup class="w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-combobox-empty>
                <div class="py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400">No matches</div>
              </fs-combobox-empty>
              <fs-combobox-list class="outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0">${REGIONS.map(
                region => `
<fs-combobox-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white" value="${region}">
  <fs-combobox-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span class="col-start-2">${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Container image</fs-field-label>
        <fs-autocomplete-input class="h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner class="outline-none data-empty:hidden" side-offset="4">
            <fs-autocomplete-popup class="w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-autocomplete-list class="max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0">${IMAGES.map(
                image => `
<fs-autocomplete-item class="flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white">
  <span>${image.name}</span>
  <span class="font-mono whitespace-nowrap text-xs opacity-80">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverType">
      <fs-select-root required="">
        <div class="w-fit space-y-1">
          <fs-select-label class="cursor-default text-sm font-bold text-neutral-950 dark:text-white">Server type</fs-select-label>
          <fs-select-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:font-[inherit] [&::part(trigger)]:border-solid [&::part(trigger)]:p-0 [&::part(trigger)]:flex [&::part(trigger)]:h-8 [&::part(trigger)]:min-w-40 [&::part(trigger)]:cursor-default [&::part(trigger)]:items-center [&::part(trigger)]:justify-between [&::part(trigger)]:gap-3 [&::part(trigger)]:border [&::part(trigger)]:border-neutral-950 [&::part(trigger)]:bg-white [&::part(trigger)]:pl-2 [&::part(trigger)]:pr-1 [&::part(trigger)]:text-sm [&::part(trigger)]:font-normal [&::part(trigger)]:text-neutral-950 [&::part(trigger)]:select-none not-data-disabled:[&::part(trigger)]:hover:bg-neutral-100 not-data-disabled:[&::part(trigger)]:active:bg-neutral-200 data-disabled:[&::part(trigger)]:border-neutral-500 data-disabled:[&::part(trigger)]:text-neutral-500 data-pressed:[&::part(trigger)]:bg-neutral-100 [&::part(trigger):focus-visible]:outline-2 [&::part(trigger):focus-visible]:-outline-offset-1 [&::part(trigger):focus-visible]:outline-neutral-950 dark:[&::part(trigger):focus-visible]:outline-white dark:[&::part(trigger)]:border-white dark:[&::part(trigger)]:bg-neutral-950 dark:[&::part(trigger)]:text-white dark:not-data-disabled:[&::part(trigger)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(trigger)]:active:bg-neutral-700 dark:data-disabled:[&::part(trigger)]:border-neutral-400 dark:data-disabled:[&::part(trigger)]:text-neutral-400 dark:data-pressed:[&::part(trigger)]:bg-neutral-800 [&::part(trigger)]:w-48">
            <fs-select-value class="data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400"></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner class="outline-none select-none z-10" side-offset="4">
            <fs-select-popup class="group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-select-scroll-up-arrow class="top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950"></fs-select-scroll-up-arrow>
              <fs-select-list class="relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6">${SERVER_TYPES.map(
                item => `
<fs-select-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950">
  <fs-select-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text class="col-start-2">${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow class="bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950"></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="numOfInstances">
      <fs-number-field-root class="flex flex-col items-start gap-1" min="1" max="64" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Number of instances</fs-field-label>
        <fs-number-field-group class="[&::part(group)]:flex [&::part(group)]:h-8">
          <fs-number-field-decrement class="[&::part(decrement)]:box-border [&::part(decrement)]:m-0 [&::part(decrement)]:p-0 [&::part(decrement)]:border-solid [&::part(decrement)]:[font-family:inherit] [&::part(decrement)]:[font-size:inherit] [&::part(decrement)]:[font-weight:inherit] [&::part(decrement)]:[line-height:inherit] [&::part(decrement)]:flex [&::part(decrement)]:h-full [&::part(decrement)]:w-8 [&::part(decrement)]:items-center [&::part(decrement)]:justify-center [&::part(decrement)]:rounded-none [&::part(decrement)]:border [&::part(decrement)]:border-neutral-950 [&::part(decrement)]:bg-white [&::part(decrement)]:bg-clip-padding [&::part(decrement)]:text-neutral-950 [&::part(decrement)]:outline-0 [&::part(decrement)]:select-none not-data-disabled:[&::part(decrement)]:hover:bg-neutral-100 not-data-disabled:[&::part(decrement)]:active:bg-neutral-200 data-disabled:[&::part(decrement)]:border-neutral-500 data-disabled:[&::part(decrement)]:text-neutral-500 [&::part(decrement):focus-visible]:z-1 [&::part(decrement):focus-visible]:outline-2 [&::part(decrement):focus-visible]:-outline-offset-1 [&::part(decrement):focus-visible]:outline-neutral-950 dark:[&::part(decrement):focus-visible]:outline-white dark:[&::part(decrement)]:border-white dark:[&::part(decrement)]:bg-neutral-950 dark:[&::part(decrement)]:text-white dark:not-data-disabled:[&::part(decrement)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(decrement)]:active:bg-neutral-700 dark:data-disabled:[&::part(decrement)]:border-neutral-400 dark:data-disabled:[&::part(decrement)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input class="h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white"></fs-number-field-input>
          <fs-number-field-increment class="[&::part(increment)]:box-border [&::part(increment)]:m-0 [&::part(increment)]:p-0 [&::part(increment)]:border-solid [&::part(increment)]:[font-family:inherit] [&::part(increment)]:[font-size:inherit] [&::part(increment)]:[font-weight:inherit] [&::part(increment)]:[line-height:inherit] [&::part(increment)]:flex [&::part(increment)]:h-full [&::part(increment)]:w-8 [&::part(increment)]:items-center [&::part(increment)]:justify-center [&::part(increment)]:rounded-none [&::part(increment)]:border [&::part(increment)]:border-neutral-950 [&::part(increment)]:bg-white [&::part(increment)]:bg-clip-padding [&::part(increment)]:text-neutral-950 [&::part(increment)]:outline-0 [&::part(increment)]:select-none not-data-disabled:[&::part(increment)]:hover:bg-neutral-100 not-data-disabled:[&::part(increment)]:active:bg-neutral-200 data-disabled:[&::part(increment)]:border-neutral-500 data-disabled:[&::part(increment)]:text-neutral-500 [&::part(increment):focus-visible]:z-1 [&::part(increment):focus-visible]:outline-2 [&::part(increment):focus-visible]:-outline-offset-1 [&::part(increment):focus-visible]:outline-neutral-950 dark:[&::part(increment):focus-visible]:outline-white dark:[&::part(increment)]:border-white dark:[&::part(increment)]:bg-neutral-950 dark:[&::part(increment)]:text-white dark:not-data-disabled:[&::part(increment)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(increment)]:active:bg-neutral-700 dark:data-disabled:[&::part(increment)]:border-neutral-400 dark:data-disabled:[&::part(increment)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="scalingThreshold">
        <fs-slider-root class="grid grid-cols-2 w-full gap-y-2" thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label class="text-sm font-bold text-neutral-950 dark:text-white">Scaling threshold</fs-slider-label>
          <fs-slider-value class="text-sm font-normal text-neutral-950 dark:text-white col-start-2 text-end"></fs-slider-value>
          <fs-slider-control class="flex col-span-2 touch-none items-center py-3 select-none">
            <fs-slider-track class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
              <fs-slider-indicator class="bg-neutral-950 select-none dark:bg-white"></fs-slider-indicator>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="storageType">
        <fs-radio-group aria-label="Storage type" class="flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white gap-4" default-value="ssd">
          <div class="text-sm font-bold text-neutral-950 dark:text-white -mt-px">Storage type</div>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'ssd' : 'SSD'}
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="hdd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'hdd' : 'HDD'}
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="restartOnFailure">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white gap-2'>
        Restart on failure
        <fs-switch-root class="flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white" default-checked="">
          <fs-switch-thumb class="[&::part(thumb)]:size-3.5 [&::part(thumb)]:bg-neutral-950 [&::part(thumb)]:transition-[translate,background-color] [&::part(thumb)]:duration-150 [&::part(thumb)]:ease-[ease] data-checked:[&::part(thumb)]:translate-x-4 data-checked:[&::part(thumb)]:bg-white dark:[&::part(thumb)]:bg-white dark:data-checked:[&::part(thumb)]:bg-neutral-950"></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols" class="flex flex-col items-start gap-1 text-neutral-950 dark:text-white">
          <div class="text-sm font-bold text-neutral-950 dark:text-white mb-2">Allowed network protocols</div>
          <div class="flex gap-4">
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="http">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="https">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssh">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button type="submit" class="[&::part(control)]:p-0 [&::part(control)]:flex [&::part(control)]:h-8 [&::part(control)]:items-center [&::part(control)]:justify-center [&::part(control)]:gap-2 [&::part(control)]:rounded-none [&::part(control)]:border [&::part(control)]:border-neutral-950 [&::part(control)]:bg-white [&::part(control)]:px-3 [&::part(control)]:py-0 [&::part(control)]:[font-family:inherit] [&::part(control)]:text-sm [&::part(control)]:leading-none [&::part(control)]:whitespace-nowrap [&::part(control)]:font-normal [&::part(control)]:text-neutral-950 [&::part(control)]:select-none not-data-disabled:[&::part(control)]:hover:bg-neutral-100 not-data-disabled:[&::part(control)]:active:bg-neutral-200 data-disabled:[&::part(control)]:border-neutral-500 data-disabled:[&::part(control)]:text-neutral-500 disabled:[&::part(control)]:border-neutral-500 disabled:[&::part(control)]:text-neutral-500 [&::part(control):focus-visible]:outline-2 [&::part(control):focus-visible]:-outline-offset-1 [&::part(control):focus-visible]:outline-neutral-950 dark:[&::part(control):focus-visible]:outline-white dark:[&::part(control)]:border-white dark:[&::part(control)]:bg-neutral-950 dark:[&::part(control)]:text-white dark:not-data-disabled:[&::part(control)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(control)]:active:bg-neutral-700 dark:data-disabled:[&::part(control)]:border-neutral-400 dark:data-disabled:[&::part(control)]:text-neutral-400 dark:disabled:[&::part(control)]:border-neutral-400 dark:disabled:[&::part(control)]:text-neutral-400 [&::part(control)]:mt-3">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

function themedFormHTML({ nativeForm = false }: FormOptions = {}): string {
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="handbook-form" aria-label="Launch new cloud server">
    <fs-field-root name="serverName">
      <fs-field-label>Server name</fs-field-label>
      <fs-field-control default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description>Must be 3 or more characters long</fs-field-description>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="region">
      <fs-combobox-root required="">
        <div>
          <fs-field-label>Region</fs-field-label>
          <fs-combobox-input-group>
            <fs-combobox-input placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div>
              <fs-combobox-clear>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner side-offset="4">
            <fs-combobox-popup>
              <fs-combobox-empty><div>No matches</div></fs-combobox-empty>
              <fs-combobox-list>${REGIONS.map(
                region => `
<fs-combobox-item value="${region}">
  <fs-combobox-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span>${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label>Container image</fs-field-label>
        <fs-autocomplete-input placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description>Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner data-fs-variant="hide-empty" side-offset="4">
            <fs-autocomplete-popup>
              <fs-autocomplete-list>${IMAGES.map(
                image => `
<fs-autocomplete-item data-fs-variant="stacked">
  <span>${image.name}</span>
  <span class="handbook-form-image-url">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="serverType">
      <fs-select-root required="">
        <div class="handbook-form-select">
          <fs-select-label>Server type</fs-select-label>
          <fs-select-trigger>
            <fs-select-value></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner side-offset="4">
            <fs-select-popup>
              <fs-select-scroll-up-arrow></fs-select-scroll-up-arrow>
              <fs-select-list>${SERVER_TYPES.map(
                item => `
<fs-select-item>
  <fs-select-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text>${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="numOfInstances">
      <fs-number-field-root min="1" max="64" required="">
        <fs-field-label>Number of instances</fs-field-label>
        <fs-number-field-group data-fs-variant="segmented">
          <fs-number-field-decrement>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input></fs-number-field-input>
          <fs-number-field-increment>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="scalingThreshold">
        <fs-slider-root thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label>Scaling threshold</fs-slider-label>
          <fs-slider-value></fs-slider-value>
          <fs-slider-control>
            <fs-slider-track>
              <fs-slider-indicator></fs-slider-indicator>
              <fs-slider-thumb index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root name="storageType">
        <fs-radio-group data-fs-variant="horizontal" aria-label="Storage type" default-value="ssd">
          <div class="handbook-form-group-label">Storage type</div>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="ssd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              SSD
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="hdd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              HDD
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root name="restartOnFailure">
      <fs-field-label>
        Restart on failure
        <fs-switch-root default-checked="">
          <fs-switch-thumb></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols">
          <div class="handbook-form-group-label handbook-form-protocol-heading">Allowed network protocols</div>
          <div class="handbook-form-protocols">
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="http">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="https">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="ssh">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button class="handbook-form-submit" type="submit">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="handbook-form-toast-viewport"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

export function configureForm(scope: ParentNode, { externalValidation = false }: FormOptions = {}) {
  const combobox = scope.querySelector('fs-combobox-root') as HTMLElement & Components.FsComboboxRoot;
  combobox.items = REGIONS;
  const autocomplete = scope.querySelector('fs-autocomplete-root') as HTMLElement & Components.FsAutocompleteRoot;
  autocomplete.items = IMAGES;
  autocomplete.itemToStringValue = (item: (typeof IMAGES)[number]) => item.url;
  scope.querySelectorAll('fs-autocomplete-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsAutocompleteItem).value = IMAGES[index];
  });
  (scope.querySelector('fs-select-root') as HTMLElement & Components.FsSelectRoot).items = SERVER_TYPES;
  scope.querySelectorAll('fs-select-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsSelectItem).value = SERVER_TYPES[index].value;
  });
  Object.assign(scope.querySelector('fs-slider-root')!, {
    defaultValue: [0.2, 0.8],
    format: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0 },
  });
  (scope.querySelector('fs-checkbox-group') as HTMLElement & Components.FsCheckboxGroup).defaultValue = [];
  if (externalValidation) {
    scope.querySelectorAll('[required], [minlength], [pattern]').forEach(element => {
      for (const name of ['required', 'minlength', 'pattern']) element.removeAttribute(name);
    });
    scope.querySelectorAll('fs-field-root').forEach(element => Object.assign(element, { invalid: false, touched: false, dirty: false }));
    scope.querySelectorAll('fs-field-error').forEach(element => {
      (element as HTMLElement & Components.FsFieldError).match = false;
      element.append(element.ownerDocument.createElement('span'));
    });
  }
  scope.querySelector('form')?.setAttribute('novalidate', '');
}

export function createForm(container: HTMLElement, options: FormOptions = {}) {
  const template = container.ownerDocument.createElement('template');
  template.innerHTML = formHTML(options);
  const content = template.content;
  // Arrays, item objects and callbacks are properties, not JSON attributes.
  // Set them before connecting the elements, including the initially offline Portal parts.
  configureForm(content, options);
  const provider = content.querySelector('fs-toast-provider') as HTMLElement & Components.FsToastProvider;
  const form = content.querySelector('fs-form, form') as HTMLElement & Components.FsForm;
  const fields = Object.fromEntries(fieldNames.map(name => [name, content.querySelector(`fs-field-root[name="${name}"]`)!])) as Record<
    keyof FormValues,
    HTMLElement & Components.FsFieldRoot
  >;
  const controls = Object.fromEntries(
    fieldNames.map(name => [
      name,
      fields[name].querySelector(
        'fs-field-control, fs-combobox-root, fs-autocomplete-root, fs-select-root, fs-number-field-root, fs-slider-root, fs-radio-group, fs-switch-root, fs-checkbox-group',
      )!,
    ]),
  ) as Record<keyof FormValues, HTMLElement>;
  const errors = Object.fromEntries(fieldNames.map(name => [name, fields[name].querySelector('fs-field-error')])) as Record<
    keyof FormValues,
    (HTMLElement & Components.FsFieldError) | null
  >;
  const toastViewport = content.querySelector('fs-toast-viewport')!;
  container.append(content);
  return { provider, form, fields, controls, errors, toastViewport, destroy: () => provider.remove() };
}
export type FormElements = ReturnType<typeof createForm>;
```

```tsx
/* button.tsx */
import * as React from 'react';
import { Button as BaseButton } from '@base-ui/react/button';
import clsx from 'clsx';

export function Button({ className, ...props }: React.ComponentPropsWithoutRef<'button'>) {
  return (
    <BaseButton
      type="button"
      className={clsx(
        'flex h-8 items-center justify-center gap-2 rounded-none border border-neutral-950 bg-white px-3 py-0 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 disabled:border-neutral-500 disabled:text-neutral-500 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:disabled:border-neutral-400 dark:disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';

export function CheckboxGroup({ className, ...props }: BaseCheckboxGroup.Props) {
  return <BaseCheckboxGroup className={clsx('flex flex-col items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* form.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Form as BaseForm } from '@base-ui/react/form';

export function Form({ className, ...props }: BaseForm.Props) {
  return <BaseForm className={clsx('flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]', className)} {...props} />;
}
```

```tsx
/* radio-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';

export function RadioGroup<Value>({ className, ...props }: BaseRadioGroup.Props<Value>) {
  return <BaseRadioGroup className={clsx('flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* toast.tsx */
'use client';
import * as React from 'react';
import { Toast } from '@base-ui/react/toast';

function Toasts() {
  const { toasts } = Toast.useToastManager();
  return toasts.map(toast => (
    <Toast.Root
      key={toast.id}
      toast={toast}
      className="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]"
    >
      <Toast.Content className="h-full overflow-hidden p-3 transition-opacity duration-250">
        <Toast.Title className="text-sm font-bold" />
        <Toast.Description className="text-sm text-neutral-700 dark:text-neutral-300" />
        <div className="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore>
          <pre className="whitespace-pre-wrap">{JSON.stringify(toast.data, null, 2)}</pre>
        </div>
        <Toast.Close
          className="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700"
          aria-label="Close"
        >
          <XIcon />
        </Toast.Close>
      </Toast.Content>
    </Toast.Root>
  ));
}

export function ToastProvider(props: { children: React.ReactNode }) {
  return (
    <Toast.Provider limit={1}>
      {props.children}
      <Toast.Portal>
        <Toast.Viewport className="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]">
          <Toasts />
        </Toast.Viewport>
      </Toast.Portal>
    </Toast.Provider>
  );
}

export const useToastManager = Toast.useToastManager;

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m2.5 2.5 11 11m-11 0 11-11" />
    </svg>
  );
}
```

```tsx
/* autocomplete.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Autocomplete } from '@base-ui/react/autocomplete';

export function Root(props: Autocomplete.Root.Props<any>) {
  return <Autocomplete.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Autocomplete.Input.Props>(function Input(
  { className, ...props }: Autocomplete.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Autocomplete.Input
      ref={forwardedRef}
      className={clsx(
        'h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Portal(props: Autocomplete.Portal.Props) {
  return <Autocomplete.Portal {...props} />;
}

export function Positioner({ className, ...props }: Autocomplete.Positioner.Props) {
  return <Autocomplete.Positioner className={clsx('outline-none data-empty:hidden', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Autocomplete.Popup.Props) {
  return (
    <Autocomplete.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Autocomplete.List.Props) {
  return (
    <Autocomplete.List
      className={clsx('max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Autocomplete.Item.Props) {
  return (
    <Autocomplete.Item
      className={clsx(
        'flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Checkbox } from '@base-ui/react/checkbox';

export function Root({ className, ...props }: Checkbox.Root.Props) {
  return (
    <Checkbox.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Checkbox.Indicator.Props) {
  return <Checkbox.Indicator className={clsx('flex data-unchecked:hidden', className)} {...props} />;
}
```

```tsx
/* combobox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Combobox } from '@base-ui/react/combobox';

export function Root(props: Combobox.Root.Props<any, any>) {
  return <Combobox.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Combobox.Input.Props>(function Input(
  { className, ...props }: Combobox.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Combobox.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function InputGroup({ className, ...props }: Combobox.InputGroup.Props) {
  return (
    <Combobox.InputGroup
      className={clsx(
        'relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>input]:pr-[2.5rem] has-[.combobox-clear]:[&>input]:pr-[calc(0.5rem+2rem*2)]',
        className,
      )}
      {...props}
    />
  );
}

export function Clear({ className, ...props }: Combobox.Clear.Props) {
  return (
    <Combobox.Clear
      className={clsx('combobox-clear flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)}
      {...props}
    >
      <XIcon />
    </Combobox.Clear>
  );
}

export function Trigger({ className, ...props }: Combobox.Trigger.Props) {
  return <Combobox.Trigger className={clsx('flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Portal(props: Combobox.Portal.Props) {
  return <Combobox.Portal {...props} />;
}

export function Positioner({ className, ...props }: Combobox.Positioner.Props) {
  return <Combobox.Positioner className={clsx('outline-none', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Combobox.Popup.Props) {
  return (
    <Combobox.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function Empty({ className, children, ...props }: Combobox.Empty.Props) {
  return (
    <Combobox.Empty {...props}>
      {children ? <div className={clsx('py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400', className)}>{children}</div> : null}
    </Combobox.Empty>
  );
}

export function List({ className, ...props }: Combobox.List.Props) {
  return (
    <Combobox.List
      className={clsx('outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Combobox.Item.Props) {
  return (
    <Combobox.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Combobox.ItemIndicator.Props) {
  return <Combobox.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function CaretDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M12 6H4l4 4.5z" />
    </svg>
  );
}

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m4.5 4.5 7 7m-7 0 7-7" />
    </svg>
  );
}
```

```tsx
/* field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Field } from '@base-ui/react/field';

export function Root({ className, ...props }: Field.Root.Props) {
  return <Field.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Label({ className, ...props }: Field.Label.Props) {
  return (
    <Field.Label
      className={clsx(
        'text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white',
        className,
      )}
      {...props}
    />
  );
}

export function Description({ className, ...props }: Field.Description.Props) {
  return <Field.Description className={clsx('text-sm text-neutral-600 dark:text-neutral-400', className)} {...props} />;
}

export const Control = React.forwardRef<HTMLInputElement, Field.Control.Props>(function FieldControl(
  { className, ...props }: Field.Control.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Field.Control
      ref={forwardedRef}
      className={clsx(
        'h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Error({ className, ...props }: Field.Error.Props) {
  return <Field.Error className={clsx('text-sm text-red-700 dark:text-red-400', className)} {...props} />;
}

export function Item(props: Field.Item.Props) {
  return <Field.Item {...props} />;
}
```

```tsx
/* fieldset.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Fieldset } from '@base-ui/react/fieldset';

export function Root(props: Fieldset.Root.Props) {
  return <Fieldset.Root {...props} />;
}

export function Legend({ className, ...props }: Fieldset.Legend.Props) {
  return <Fieldset.Legend className={clsx('text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* number-field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { NumberField } from '@base-ui/react/number-field';

export function Root({ className, ...props }: NumberField.Root.Props) {
  return <NumberField.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Group({ className, ...props }: NumberField.Group.Props) {
  return <NumberField.Group className={clsx('flex h-8', className)} {...props} />;
}

export function Decrement({ className, ...props }: NumberField.Decrement.Props) {
  return (
    <NumberField.Decrement
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}

export const Input = React.forwardRef<HTMLInputElement, NumberField.Input.Props>(function Input(
  { className, ...props }: NumberField.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <NumberField.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white',
        className,
      )}
      {...props}
    />
  );
});

export function Increment({ className, ...props }: NumberField.Increment.Props) {
  return (
    <NumberField.Increment
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* radio.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Radio } from '@base-ui/react/radio';

export function Root({ className, ...props }: Radio.Root.Props) {
  return (
    <Radio.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Radio.Indicator.Props) {
  return <Radio.Indicator className={clsx('flex items-center justify-center data-unchecked:hidden before:size-2 before:rounded-full before:bg-current', className)} {...props} />;
}
```

```tsx
/* select.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Select } from '@base-ui/react/select';

export function Root(props: Select.Root.Props<any>) {
  return <Select.Root {...props} />;
}

export function Label({ className, ...props }: Select.Label.Props) {
  return <Select.Label className={clsx('cursor-default text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Trigger({ className, ...props }: Select.Trigger.Props) {
  return (
    <Select.Trigger
      className={clsx(
        'flex h-8 min-w-40 cursor-default items-center justify-between gap-3 border border-neutral-950 bg-white pl-2 pr-1 text-sm font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 data-pressed:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:data-pressed:bg-neutral-800',
        className,
      )}
      {...props}
    />
  );
}

export function Value({ className, ...props }: Select.Value.Props) {
  return <Select.Value className={clsx('data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400', className)} {...props} />;
}

export function Icon(props: Select.Icon.Props) {
  return <Select.Icon {...props} />;
}

export function Portal(props: Select.Portal.Props) {
  return <Select.Portal {...props} />;
}

export function Positioner({ className, ...props }: Select.Positioner.Props) {
  return <Select.Positioner className={clsx('outline-none select-none z-10', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Select.Popup.Props) {
  return (
    <Select.Popup
      className={clsx(
        'group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function ScrollUpArrow({ className, ...props }: Select.ScrollUpArrow.Props) {
  return (
    <Select.ScrollUpArrow
      className={clsx(
        "top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function ScrollDownArrow({ className, ...props }: Select.ScrollDownArrow.Props) {
  return (
    <Select.ScrollDownArrow
      className={clsx(
        "bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Select.List.Props) {
  return <Select.List className={clsx('relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6', className)} {...props} />;
}

export function Item({ className, ...props }: Select.Item.Props) {
  return (
    <Select.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Select.ItemIndicator.Props) {
  return <Select.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function ItemText({ className, ...props }: Select.ItemText.Props) {
  return <Select.ItemText className={clsx('col-start-2', className)} {...props} />;
}
```

```tsx
/* slider.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Slider } from '@base-ui/react/slider';

export function Root({ className, ...props }: Slider.Root.Props<any>) {
  return <Slider.Root className={clsx('grid grid-cols-2', className)} {...props} />;
}

export function Value({ className, ...props }: Slider.Value.Props) {
  return <Slider.Value className={clsx('text-sm font-normal text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Control({ className, ...props }: Slider.Control.Props) {
  return <Slider.Control className={clsx('flex col-span-2 touch-none items-center py-3 select-none', className)} {...props} />;
}

export function Track({ className, ...props }: Slider.Track.Props) {
  return <Slider.Track className={clsx('h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800', className)} {...props} />;
}

export function Indicator({ className, ...props }: Slider.Indicator.Props) {
  return <Slider.Indicator className={clsx('bg-neutral-950 select-none dark:bg-white', className)} {...props} />;
}

export function Thumb({ className, ...props }: Slider.Thumb.Props) {
  return (
    <Slider.Thumb
      className={clsx(
        'size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* switch.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Switch } from '@base-ui/react/switch';

export function Root({ className, ...props }: Switch.Root.Props) {
  return (
    <Switch.Root
      className={clsx(
        'flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function Thumb({ className, ...props }: Switch.Thumb.Props) {
  return (
    <Switch.Thumb
      className={clsx(
        'size-3.5 bg-neutral-950 transition-[translate,background-color] duration-150 ease-[ease] data-checked:translate-x-4 data-checked:bg-white dark:bg-white dark:data-checked:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```ts
/* stencil-themed-hero.ts */
import { mount as mountForm } from './stencil-hero';
import './stencil-form.css';

export function mount(container: HTMLElement) {
  return mountForm(container, true);
}
```

```ts
/* stencil-hero.ts */
import { createForm } from './stencil-form';
import { connectToasts } from './stencil-toast';

export function mount(container: HTMLElement, themed = false) {
  const elements = createForm(container, { themed });
  const toasts = connectToasts(elements.provider, elements.toastViewport, themed);
  elements.form.formSubmit = values => toasts.submit(values);
  return () => {
    toasts.destroy();
    elements.destroy();
  };
}
```

```css
/* stencil-form.css */
/* Shared layout for the three theme-based Handbook forms. */
@layer fs-theme {
  .handbook-form {
    --fs-form-gap: var(--fs-space-5);
    --fs-form-max-width: 16rem;
    --fs-field-max-width: none;
    --fs-combobox-input-group-width: 16rem;
    --fs-number-field-input-width: 4rem;
    --fs-number-field-input-border: 1px solid var(--fs-color-foreground);
    --fs-slider-root-width: 100%;
    --fs-slider-control-width: 100%;
    --fs-slider-label-font-weight: var(--fs-font-weight-bold);
    --fs-slider-root-row-gap: var(--fs-space-2);
    --fs-select-width: 12rem;
    --fs-select-line-height: var(--fs-line-height-sm);
  }
  /* TanStack's adapter owns a native form instead of fs-form. */
  form.handbook-form {
    display: flex;
    flex-direction: column;
    gap: var(--fs-form-gap);
    width: 100%;
    max-width: var(--fs-form-max-width);
  }
  .handbook-form-select {
    display: flex;
    flex-direction: column;
    gap: var(--fs-space-1);
    width: fit-content;
  }
  .handbook-form-group-label {
    font-size: var(--fs-font-size-sm);
    line-height: var(--fs-line-height-sm);
    font-weight: var(--fs-font-weight-bold);
    color: var(--fs-color-foreground);
  }
  :where([data-fs-variant='horizontal']) .handbook-form-group-label {
    margin-top: -1px;
  }
  .handbook-form-protocol-heading {
    margin-bottom: var(--fs-space-2);
  }
  .handbook-form-protocols {
    display: flex;
    gap: var(--fs-space-4);
  }
  .handbook-form-protocol-label {
    text-transform: uppercase;
  }
  .handbook-form-submit::part(control) {
    margin-top: var(--fs-space-3);
  }
  .handbook-form-image-url {
    font-family: 'Paper Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
    white-space: nowrap;
    font-size: 0.75rem;
    opacity: 0.8;
  }
  .handbook-form-toast-viewport {
    --fs-toast-viewport-z-index: 10;
    --fs-toast-viewport-width: 250px;
    --fs-toast-viewport-bottom: 1rem;
    --fs-toast-viewport-right: 1rem;
  }
  .handbook-form-submitted-values {
    margin-top: var(--fs-space-2);
    border: var(--fs-border-width) solid var(--fs-color-foreground);
    padding: var(--fs-space-2);
    font-size: 0.75rem;
    user-select: text;
  }
  .handbook-form-submitted-values pre {
    white-space: pre-wrap;
    font-size: 0.75rem;
    line-height: calc(1 / 0.75);
  }
  @media (min-width: 40rem) {
    .handbook-form {
      --fs-form-max-width: 20rem;
    }
    .handbook-form-toast-viewport {
      --fs-toast-viewport-width: 360px;
      --fs-toast-viewport-bottom: 2rem;
      --fs-toast-viewport-right: 2rem;
    }
  }
  @media (min-width: 48rem) {
    .handbook-form {
      --fs-autocomplete-input-width: 20rem;
    }
  }
}
```

```ts
/* stencil-toast.ts */
import { createToastManager, type ToastObject } from 'finesoft-components/toast';
import type { Components } from 'finesoft-components';

const toastHTML = `
<fs-toast-root class="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]">
  <fs-toast-content class="h-full overflow-hidden p-3 transition-opacity duration-250">
    <fs-toast-title class="text-sm font-bold"></fs-toast-title>
    <fs-toast-description class="text-sm text-neutral-700 dark:text-neutral-300"></fs-toast-description>
    <div class="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore="true">
      <pre class="whitespace-pre-wrap"></pre>
    </div>
    <fs-toast-close class="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700" aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

const themedToastHTML = `
<fs-toast-root data-fs-variant="rich">
  <fs-toast-content>
    <fs-toast-title></fs-toast-title>
    <fs-toast-description></fs-toast-description>
    <div class="handbook-form-submitted-values" data-base-ui-swipe-ignore="true">
      <pre></pre>
    </div>
    <fs-toast-close aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

export function connectToasts(provider: HTMLElement & Components.FsToastProvider, viewport: Element, themed = false) {
  const manager = createToastManager();
  const roots = new Map<string, HTMLElement & Components.FsToastRoot>();
  function update(event: CustomEvent<ToastObject[]>) {
    const toasts = event.detail;
    for (const [id, root] of roots) {
      if (!toasts.some(toast => toast.id === id)) {
        root.remove();
        roots.delete(id);
      }
    }
    for (const toast of toasts) {
      let root = roots.get(toast.id);
      if (!root) {
        const template = provider.ownerDocument.createElement('template');
        template.innerHTML = themed ? themedToastHTML : toastHTML;
        root = template.content.firstElementChild as HTMLElement & Components.FsToastRoot;
        root.toast = toast;
        root.querySelector('pre')!.textContent = JSON.stringify(toast.data, null, 2);
        roots.set(toast.id, root);
        viewport.append(root);
      } else {
        root.toast = toast;
      }
    }
  }
  provider.addEventListener('toastsChange', update as EventListener);
  provider.toastManager = manager;
  return {
    submit: (data: unknown) => manager.add({ title: 'Form submitted', description: 'The form contains these values:', data: data as Record<string, unknown> }),
    destroy: () => provider.removeEventListener('toastsChange', update as EventListener),
  };
}
```

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactExample from './react-hero';
import StencilExample from './docs-native-preview';
import { formHTML, configureForm } from './stencil-form';

export default function Comparison() {
  const options = {};
  return (
    <StencilComparison
      component="handbook-form-hero"
      react={<ReactExample />}
      stencil={null}
      renderSource={() => formHTML(options)}
      beforeHydrate={document => configureForm(document, options)}
      clientStencil={<StencilExample />}
    />
  );
}
```

```tsx
/* react-hero.tsx */
'use client';
import * as React from 'react';
import { Button } from './button';
import { CheckboxGroup } from './checkbox-group';
import { Form } from './form';
import { RadioGroup } from './radio-group';
import { ToastProvider, useToastManager } from './toast';
import * as Autocomplete from './autocomplete';
import * as Checkbox from './checkbox';
import * as Combobox from './combobox';
import * as Field from './field';
import * as Fieldset from './fieldset';
import * as NumberField from './number-field';
import * as Radio from './radio';
import * as Select from './select';
import * as Slider from './slider';
import * as Switch from './switch';

function ExampleForm() {
  const toastManager = useToastManager();
  return (
    <Form
      aria-label="Launch new cloud server"
      onFormSubmit={formValues => {
        toastManager.add({
          title: 'Form submitted',
          description: 'The form contains these values:',
          data: formValues,
        });
      }}
    >
      <Field.Root name="serverName">
        <Field.Label>Server name</Field.Label>
        <Field.Control defaultValue="" placeholder="e.g. api-server-01" required minLength={3} pattern=".*[A-Za-z].*" />
        <Field.Description>Must be 3 or more characters long</Field.Description>
        <Field.Error />
      </Field.Root>

      <Field.Root name="region">
        <Combobox.Root items={REGIONS} required>
          <div className="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
            <Field.Label className="mb-1 block">Region</Field.Label>
            <Combobox.InputGroup>
              <Combobox.Input placeholder="e.g. eu-central-1" />
              <div className="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
                <Combobox.Clear />
                <Combobox.Trigger>
                  <Combobox.CaretDownIcon />
                </Combobox.Trigger>
              </div>
            </Combobox.InputGroup>
          </div>
          <Combobox.Portal>
            <Combobox.Positioner>
              <Combobox.Popup>
                <Combobox.Empty>No matches</Combobox.Empty>
                <Combobox.List>
                  {(region: string) => {
                    return (
                      <Combobox.Item key={region} value={region}>
                        <Combobox.ItemIndicator>
                          <CheckIcon />
                        </Combobox.ItemIndicator>
                        <span className="col-start-2">{region}</span>
                      </Combobox.Item>
                    );
                  }}
                </Combobox.List>
              </Combobox.Popup>
            </Combobox.Positioner>
          </Combobox.Portal>
        </Combobox.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="containerImage">
        <Autocomplete.Root items={IMAGES} mode="both" itemToStringValue={(itemValue: Image) => itemValue.url} required>
          <Field.Label>Container image</Field.Label>
          <Autocomplete.Input placeholder="e.g. docker.io/library/node:latest" />
          <Field.Description>Enter a registry URL with optional tags</Field.Description>
          <Autocomplete.Portal>
            <Autocomplete.Positioner>
              <Autocomplete.Popup>
                <Autocomplete.List>
                  {(image: Image) => {
                    return (
                      <Autocomplete.Item key={image.url} value={image}>
                        <span>{image.name}</span>
                        <span className="font-mono whitespace-nowrap text-xs opacity-80">{image.url}</span>
                      </Autocomplete.Item>
                    );
                  }}
                </Autocomplete.List>
              </Autocomplete.Popup>
            </Autocomplete.Positioner>
          </Autocomplete.Portal>
        </Autocomplete.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="serverType">
        <Select.Root items={SERVER_TYPES} required>
          <div className="w-fit space-y-1">
            <Select.Label>Server type</Select.Label>
            <Select.Trigger className="w-48">
              <Select.Value />
              <Select.Icon>
                <CaretUpDownIcon />
              </Select.Icon>
            </Select.Trigger>
          </div>
          <Select.Portal>
            <Select.Positioner>
              <Select.Popup>
                <Select.ScrollUpArrow />
                <Select.List>
                  {SERVER_TYPES.map(({ label, value }) => {
                    return (
                      <Select.Item key={value} value={value}>
                        <Select.ItemIndicator>
                          <CheckIcon />
                        </Select.ItemIndicator>
                        <Select.ItemText>{label}</Select.ItemText>
                      </Select.Item>
                    );
                  })}
                </Select.List>
                <Select.ScrollDownArrow />
              </Select.Popup>
            </Select.Positioner>
          </Select.Portal>
        </Select.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="numOfInstances">
        <NumberField.Root defaultValue={undefined} min={1} max={64} required>
          <Field.Label>Number of instances</Field.Label>
          <NumberField.Group>
            <NumberField.Decrement>
              <MinusIcon />
            </NumberField.Decrement>
            <NumberField.Input />
            <NumberField.Increment>
              <PlusIcon />
            </NumberField.Increment>
          </NumberField.Group>
        </NumberField.Root>
        <Field.Error />
      </Field.Root>

      <Field.Root name="scalingThreshold">
        <Fieldset.Root
          render={
            <Slider.Root
              defaultValue={[0.2, 0.8]}
              thumbAlignment="edge"
              min={0}
              max={1}
              step={0.01}
              format={{
                style: 'percent',
                minimumFractionDigits: 0,
                maximumFractionDigits: 0,
              }}
              className="w-full gap-y-2"
            />
          }
        >
          <Fieldset.Legend>Scaling threshold</Fieldset.Legend>
          <Slider.Value className="col-start-2 text-end" />
          <Slider.Control>
            <Slider.Track>
              <Slider.Indicator />
              <Slider.Thumb index={0} aria-label="Minimum threshold" />
              <Slider.Thumb index={1} aria-label="Maximum threshold" />
            </Slider.Track>
          </Slider.Control>
        </Fieldset.Root>
      </Field.Root>

      <Field.Root name="storageType">
        <Fieldset.Root render={<RadioGroup<'ssd' | 'hdd'> className="gap-4" defaultValue="ssd" />}>
          <Fieldset.Legend className="-mt-px">Storage type</Fieldset.Legend>
          <Field.Item>
            <Field.Label>
              <Radio.Root value="ssd">
                <Radio.Indicator />
              </Radio.Root>
              SSD
            </Field.Label>
          </Field.Item>
          <Field.Item>
            <Field.Label>
              <Radio.Root value="hdd">
                <Radio.Indicator />
              </Radio.Root>
              HDD
            </Field.Label>
          </Field.Item>
        </Fieldset.Root>
      </Field.Root>

      <Field.Root name="restartOnFailure">
        <Field.Label className="gap-2">
          Restart on failure
          <Switch.Root defaultChecked>
            <Switch.Thumb />
          </Switch.Root>
        </Field.Label>
      </Field.Root>

      <Field.Root name="allowedNetworkProtocols">
        <Fieldset.Root render={<CheckboxGroup defaultValue={[]} />}>
          <Fieldset.Legend className="mb-2">Allowed network protocols</Fieldset.Legend>
          <div className="flex gap-4">
            {['http', 'https', 'ssh'].map(val => {
              return (
                <Field.Item key={val}>
                  <Field.Label className="uppercase">
                    <Checkbox.Root value={val}>
                      <Checkbox.Indicator>
                        <CheckIcon />
                      </Checkbox.Indicator>
                    </Checkbox.Root>
                    {val}
                  </Field.Label>
                </Field.Item>
              );
            })}
          </div>
        </Fieldset.Root>
      </Field.Root>

      <Button type="submit" className="mt-3">
        Launch server
      </Button>
    </Form>
  );
}

export default function App() {
  return (
    <ToastProvider>
      <ExampleForm />
    </ToastProvider>
  );
}

function CaretUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="m2.5 8.5 4 4 7-9" />
    </svg>
  );
}

function PlusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13M8 14.5v-13" />
    </svg>
  );
}

function MinusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13" />
    </svg>
  );
}

function cartesian<T extends string[][]>(...arrays: T): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}

const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));

interface Image {
  url: string;
  name: string;
}
/* prettier-ignore */
const IMAGES: Image[] = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map((name) => ({
  url: `docker.io/library/${name}`,
  name,
}));

const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];
```

```tsx
/* docs-native-preview.tsx */
'use client';
import { NativeStencilPreview } from 'docs/src/components/NativeStencilPreview';
import { mount } from './stencil-hero';
export default function Preview() {
  return <NativeStencilPreview mount={mount} />;
}
```

```ts
/* stencil-form.ts */
import type { Components } from 'finesoft-components';

export interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

export const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};
export const fieldNames = Object.keys(defaultValues) as Array<keyof FormValues>;
export interface FormOptions {
  externalValidation?: boolean;
  nativeForm?: boolean;
  themed?: boolean;
}

function cartesian(...arrays: string[][]): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}
const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));
const IMAGES = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map(name => ({ name, url: `docker.io/library/${name}` }));
const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];

// This same Web Components declaration is used by the browser and by Stencil SSR.
// The framework integrations below only exchange public properties and events.
export function formHTML(options: FormOptions = {}): string {
  if (options.themed) return themedFormHTML(options);
  const { nativeForm = false } = options;
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]" aria-label="Launch new cloud server">
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverName">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Server name</fs-field-label>
      <fs-field-control class="h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Must be 3 or more characters long</fs-field-description>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="region">
      <fs-combobox-root required="">
        <div class="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
          <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white mb-1 block'>Region</fs-field-label>
          <fs-combobox-input-group class="relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>fs-combobox-input>input]:pr-[2.5rem] has-[.combobox-clear]:[&>fs-combobox-input>input]:pr-[calc(0.5rem+2rem*2)]">
            <fs-combobox-input class="h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div class="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
              <fs-combobox-clear class="[&::part(clear)]:box-border [&::part(clear)]:m-0 [&::part(clear)]:p-0 [&::part(clear)]:border-solid [&::part(clear)]:[font-family:inherit] [&::part(clear)]:[font-size:inherit] [&::part(clear)]:[font-weight:inherit] [&::part(clear)]:[line-height:inherit] combobox-clear [&::part(clear)]:flex [&::part(clear)]:h-full [&::part(clear)]:w-6 [&::part(clear)]:items-center [&::part(clear)]:justify-center [&::part(clear)]:border-0 [&::part(clear)]:bg-transparent [&::part(clear)]:p-0 [&::part(clear)]:text-neutral-950 dark:[&::part(clear)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:p-0 [&::part(trigger)]:border-solid [&::part(trigger)]:[font-family:inherit] [&::part(trigger)]:[font-size:inherit] [&::part(trigger)]:[font-weight:inherit] [&::part(trigger)]:[line-height:inherit] [&::part(trigger)]:flex [&::part(trigger)]:h-full [&::part(trigger)]:w-6 [&::part(trigger)]:items-center [&::part(trigger)]:justify-center [&::part(trigger)]:border-0 [&::part(trigger)]:bg-transparent [&::part(trigger)]:p-0 [&::part(trigger)]:text-neutral-950 dark:[&::part(trigger)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner class="outline-none" side-offset="4">
            <fs-combobox-popup class="w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-combobox-empty>
                <div class="py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400">No matches</div>
              </fs-combobox-empty>
              <fs-combobox-list class="outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0">${REGIONS.map(
                region => `
<fs-combobox-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white" value="${region}">
  <fs-combobox-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span class="col-start-2">${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Container image</fs-field-label>
        <fs-autocomplete-input class="h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner class="outline-none data-empty:hidden" side-offset="4">
            <fs-autocomplete-popup class="w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-autocomplete-list class="max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0">${IMAGES.map(
                image => `
<fs-autocomplete-item class="flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white">
  <span>${image.name}</span>
  <span class="font-mono whitespace-nowrap text-xs opacity-80">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverType">
      <fs-select-root required="">
        <div class="w-fit space-y-1">
          <fs-select-label class="cursor-default text-sm font-bold text-neutral-950 dark:text-white">Server type</fs-select-label>
          <fs-select-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:font-[inherit] [&::part(trigger)]:border-solid [&::part(trigger)]:p-0 [&::part(trigger)]:flex [&::part(trigger)]:h-8 [&::part(trigger)]:min-w-40 [&::part(trigger)]:cursor-default [&::part(trigger)]:items-center [&::part(trigger)]:justify-between [&::part(trigger)]:gap-3 [&::part(trigger)]:border [&::part(trigger)]:border-neutral-950 [&::part(trigger)]:bg-white [&::part(trigger)]:pl-2 [&::part(trigger)]:pr-1 [&::part(trigger)]:text-sm [&::part(trigger)]:font-normal [&::part(trigger)]:text-neutral-950 [&::part(trigger)]:select-none not-data-disabled:[&::part(trigger)]:hover:bg-neutral-100 not-data-disabled:[&::part(trigger)]:active:bg-neutral-200 data-disabled:[&::part(trigger)]:border-neutral-500 data-disabled:[&::part(trigger)]:text-neutral-500 data-pressed:[&::part(trigger)]:bg-neutral-100 [&::part(trigger):focus-visible]:outline-2 [&::part(trigger):focus-visible]:-outline-offset-1 [&::part(trigger):focus-visible]:outline-neutral-950 dark:[&::part(trigger):focus-visible]:outline-white dark:[&::part(trigger)]:border-white dark:[&::part(trigger)]:bg-neutral-950 dark:[&::part(trigger)]:text-white dark:not-data-disabled:[&::part(trigger)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(trigger)]:active:bg-neutral-700 dark:data-disabled:[&::part(trigger)]:border-neutral-400 dark:data-disabled:[&::part(trigger)]:text-neutral-400 dark:data-pressed:[&::part(trigger)]:bg-neutral-800 [&::part(trigger)]:w-48">
            <fs-select-value class="data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400"></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner class="outline-none select-none z-10" side-offset="4">
            <fs-select-popup class="group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-select-scroll-up-arrow class="top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950"></fs-select-scroll-up-arrow>
              <fs-select-list class="relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6">${SERVER_TYPES.map(
                item => `
<fs-select-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950">
  <fs-select-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text class="col-start-2">${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow class="bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950"></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="numOfInstances">
      <fs-number-field-root class="flex flex-col items-start gap-1" min="1" max="64" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Number of instances</fs-field-label>
        <fs-number-field-group class="[&::part(group)]:flex [&::part(group)]:h-8">
          <fs-number-field-decrement class="[&::part(decrement)]:box-border [&::part(decrement)]:m-0 [&::part(decrement)]:p-0 [&::part(decrement)]:border-solid [&::part(decrement)]:[font-family:inherit] [&::part(decrement)]:[font-size:inherit] [&::part(decrement)]:[font-weight:inherit] [&::part(decrement)]:[line-height:inherit] [&::part(decrement)]:flex [&::part(decrement)]:h-full [&::part(decrement)]:w-8 [&::part(decrement)]:items-center [&::part(decrement)]:justify-center [&::part(decrement)]:rounded-none [&::part(decrement)]:border [&::part(decrement)]:border-neutral-950 [&::part(decrement)]:bg-white [&::part(decrement)]:bg-clip-padding [&::part(decrement)]:text-neutral-950 [&::part(decrement)]:outline-0 [&::part(decrement)]:select-none not-data-disabled:[&::part(decrement)]:hover:bg-neutral-100 not-data-disabled:[&::part(decrement)]:active:bg-neutral-200 data-disabled:[&::part(decrement)]:border-neutral-500 data-disabled:[&::part(decrement)]:text-neutral-500 [&::part(decrement):focus-visible]:z-1 [&::part(decrement):focus-visible]:outline-2 [&::part(decrement):focus-visible]:-outline-offset-1 [&::part(decrement):focus-visible]:outline-neutral-950 dark:[&::part(decrement):focus-visible]:outline-white dark:[&::part(decrement)]:border-white dark:[&::part(decrement)]:bg-neutral-950 dark:[&::part(decrement)]:text-white dark:not-data-disabled:[&::part(decrement)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(decrement)]:active:bg-neutral-700 dark:data-disabled:[&::part(decrement)]:border-neutral-400 dark:data-disabled:[&::part(decrement)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input class="h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white"></fs-number-field-input>
          <fs-number-field-increment class="[&::part(increment)]:box-border [&::part(increment)]:m-0 [&::part(increment)]:p-0 [&::part(increment)]:border-solid [&::part(increment)]:[font-family:inherit] [&::part(increment)]:[font-size:inherit] [&::part(increment)]:[font-weight:inherit] [&::part(increment)]:[line-height:inherit] [&::part(increment)]:flex [&::part(increment)]:h-full [&::part(increment)]:w-8 [&::part(increment)]:items-center [&::part(increment)]:justify-center [&::part(increment)]:rounded-none [&::part(increment)]:border [&::part(increment)]:border-neutral-950 [&::part(increment)]:bg-white [&::part(increment)]:bg-clip-padding [&::part(increment)]:text-neutral-950 [&::part(increment)]:outline-0 [&::part(increment)]:select-none not-data-disabled:[&::part(increment)]:hover:bg-neutral-100 not-data-disabled:[&::part(increment)]:active:bg-neutral-200 data-disabled:[&::part(increment)]:border-neutral-500 data-disabled:[&::part(increment)]:text-neutral-500 [&::part(increment):focus-visible]:z-1 [&::part(increment):focus-visible]:outline-2 [&::part(increment):focus-visible]:-outline-offset-1 [&::part(increment):focus-visible]:outline-neutral-950 dark:[&::part(increment):focus-visible]:outline-white dark:[&::part(increment)]:border-white dark:[&::part(increment)]:bg-neutral-950 dark:[&::part(increment)]:text-white dark:not-data-disabled:[&::part(increment)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(increment)]:active:bg-neutral-700 dark:data-disabled:[&::part(increment)]:border-neutral-400 dark:data-disabled:[&::part(increment)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="scalingThreshold">
        <fs-slider-root class="grid grid-cols-2 w-full gap-y-2" thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label class="text-sm font-bold text-neutral-950 dark:text-white">Scaling threshold</fs-slider-label>
          <fs-slider-value class="text-sm font-normal text-neutral-950 dark:text-white col-start-2 text-end"></fs-slider-value>
          <fs-slider-control class="flex col-span-2 touch-none items-center py-3 select-none">
            <fs-slider-track class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
              <fs-slider-indicator class="bg-neutral-950 select-none dark:bg-white"></fs-slider-indicator>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="storageType">
        <fs-radio-group aria-label="Storage type" class="flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white gap-4" default-value="ssd">
          <div class="text-sm font-bold text-neutral-950 dark:text-white -mt-px">Storage type</div>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'ssd' : 'SSD'}
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="hdd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'hdd' : 'HDD'}
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="restartOnFailure">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white gap-2'>
        Restart on failure
        <fs-switch-root class="flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white" default-checked="">
          <fs-switch-thumb class="[&::part(thumb)]:size-3.5 [&::part(thumb)]:bg-neutral-950 [&::part(thumb)]:transition-[translate,background-color] [&::part(thumb)]:duration-150 [&::part(thumb)]:ease-[ease] data-checked:[&::part(thumb)]:translate-x-4 data-checked:[&::part(thumb)]:bg-white dark:[&::part(thumb)]:bg-white dark:data-checked:[&::part(thumb)]:bg-neutral-950"></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols" class="flex flex-col items-start gap-1 text-neutral-950 dark:text-white">
          <div class="text-sm font-bold text-neutral-950 dark:text-white mb-2">Allowed network protocols</div>
          <div class="flex gap-4">
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="http">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="https">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssh">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button type="submit" class="[&::part(control)]:p-0 [&::part(control)]:flex [&::part(control)]:h-8 [&::part(control)]:items-center [&::part(control)]:justify-center [&::part(control)]:gap-2 [&::part(control)]:rounded-none [&::part(control)]:border [&::part(control)]:border-neutral-950 [&::part(control)]:bg-white [&::part(control)]:px-3 [&::part(control)]:py-0 [&::part(control)]:[font-family:inherit] [&::part(control)]:text-sm [&::part(control)]:leading-none [&::part(control)]:whitespace-nowrap [&::part(control)]:font-normal [&::part(control)]:text-neutral-950 [&::part(control)]:select-none not-data-disabled:[&::part(control)]:hover:bg-neutral-100 not-data-disabled:[&::part(control)]:active:bg-neutral-200 data-disabled:[&::part(control)]:border-neutral-500 data-disabled:[&::part(control)]:text-neutral-500 disabled:[&::part(control)]:border-neutral-500 disabled:[&::part(control)]:text-neutral-500 [&::part(control):focus-visible]:outline-2 [&::part(control):focus-visible]:-outline-offset-1 [&::part(control):focus-visible]:outline-neutral-950 dark:[&::part(control):focus-visible]:outline-white dark:[&::part(control)]:border-white dark:[&::part(control)]:bg-neutral-950 dark:[&::part(control)]:text-white dark:not-data-disabled:[&::part(control)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(control)]:active:bg-neutral-700 dark:data-disabled:[&::part(control)]:border-neutral-400 dark:data-disabled:[&::part(control)]:text-neutral-400 dark:disabled:[&::part(control)]:border-neutral-400 dark:disabled:[&::part(control)]:text-neutral-400 [&::part(control)]:mt-3">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

function themedFormHTML({ nativeForm = false }: FormOptions = {}): string {
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="handbook-form" aria-label="Launch new cloud server">
    <fs-field-root name="serverName">
      <fs-field-label>Server name</fs-field-label>
      <fs-field-control default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description>Must be 3 or more characters long</fs-field-description>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="region">
      <fs-combobox-root required="">
        <div>
          <fs-field-label>Region</fs-field-label>
          <fs-combobox-input-group>
            <fs-combobox-input placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div>
              <fs-combobox-clear>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner side-offset="4">
            <fs-combobox-popup>
              <fs-combobox-empty><div>No matches</div></fs-combobox-empty>
              <fs-combobox-list>${REGIONS.map(
                region => `
<fs-combobox-item value="${region}">
  <fs-combobox-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span>${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label>Container image</fs-field-label>
        <fs-autocomplete-input placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description>Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner data-fs-variant="hide-empty" side-offset="4">
            <fs-autocomplete-popup>
              <fs-autocomplete-list>${IMAGES.map(
                image => `
<fs-autocomplete-item data-fs-variant="stacked">
  <span>${image.name}</span>
  <span class="handbook-form-image-url">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="serverType">
      <fs-select-root required="">
        <div class="handbook-form-select">
          <fs-select-label>Server type</fs-select-label>
          <fs-select-trigger>
            <fs-select-value></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner side-offset="4">
            <fs-select-popup>
              <fs-select-scroll-up-arrow></fs-select-scroll-up-arrow>
              <fs-select-list>${SERVER_TYPES.map(
                item => `
<fs-select-item>
  <fs-select-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text>${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="numOfInstances">
      <fs-number-field-root min="1" max="64" required="">
        <fs-field-label>Number of instances</fs-field-label>
        <fs-number-field-group data-fs-variant="segmented">
          <fs-number-field-decrement>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input></fs-number-field-input>
          <fs-number-field-increment>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="scalingThreshold">
        <fs-slider-root thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label>Scaling threshold</fs-slider-label>
          <fs-slider-value></fs-slider-value>
          <fs-slider-control>
            <fs-slider-track>
              <fs-slider-indicator></fs-slider-indicator>
              <fs-slider-thumb index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root name="storageType">
        <fs-radio-group data-fs-variant="horizontal" aria-label="Storage type" default-value="ssd">
          <div class="handbook-form-group-label">Storage type</div>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="ssd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              SSD
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="hdd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              HDD
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root name="restartOnFailure">
      <fs-field-label>
        Restart on failure
        <fs-switch-root default-checked="">
          <fs-switch-thumb></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols">
          <div class="handbook-form-group-label handbook-form-protocol-heading">Allowed network protocols</div>
          <div class="handbook-form-protocols">
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="http">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="https">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="ssh">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button class="handbook-form-submit" type="submit">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="handbook-form-toast-viewport"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

export function configureForm(scope: ParentNode, { externalValidation = false }: FormOptions = {}) {
  const combobox = scope.querySelector('fs-combobox-root') as HTMLElement & Components.FsComboboxRoot;
  combobox.items = REGIONS;
  const autocomplete = scope.querySelector('fs-autocomplete-root') as HTMLElement & Components.FsAutocompleteRoot;
  autocomplete.items = IMAGES;
  autocomplete.itemToStringValue = (item: (typeof IMAGES)[number]) => item.url;
  scope.querySelectorAll('fs-autocomplete-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsAutocompleteItem).value = IMAGES[index];
  });
  (scope.querySelector('fs-select-root') as HTMLElement & Components.FsSelectRoot).items = SERVER_TYPES;
  scope.querySelectorAll('fs-select-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsSelectItem).value = SERVER_TYPES[index].value;
  });
  Object.assign(scope.querySelector('fs-slider-root')!, {
    defaultValue: [0.2, 0.8],
    format: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0 },
  });
  (scope.querySelector('fs-checkbox-group') as HTMLElement & Components.FsCheckboxGroup).defaultValue = [];
  if (externalValidation) {
    scope.querySelectorAll('[required], [minlength], [pattern]').forEach(element => {
      for (const name of ['required', 'minlength', 'pattern']) element.removeAttribute(name);
    });
    scope.querySelectorAll('fs-field-root').forEach(element => Object.assign(element, { invalid: false, touched: false, dirty: false }));
    scope.querySelectorAll('fs-field-error').forEach(element => {
      (element as HTMLElement & Components.FsFieldError).match = false;
      element.append(element.ownerDocument.createElement('span'));
    });
  }
  scope.querySelector('form')?.setAttribute('novalidate', '');
}

export function createForm(container: HTMLElement, options: FormOptions = {}) {
  const template = container.ownerDocument.createElement('template');
  template.innerHTML = formHTML(options);
  const content = template.content;
  // Arrays, item objects and callbacks are properties, not JSON attributes.
  // Set them before connecting the elements, including the initially offline Portal parts.
  configureForm(content, options);
  const provider = content.querySelector('fs-toast-provider') as HTMLElement & Components.FsToastProvider;
  const form = content.querySelector('fs-form, form') as HTMLElement & Components.FsForm;
  const fields = Object.fromEntries(fieldNames.map(name => [name, content.querySelector(`fs-field-root[name="${name}"]`)!])) as Record<
    keyof FormValues,
    HTMLElement & Components.FsFieldRoot
  >;
  const controls = Object.fromEntries(
    fieldNames.map(name => [
      name,
      fields[name].querySelector(
        'fs-field-control, fs-combobox-root, fs-autocomplete-root, fs-select-root, fs-number-field-root, fs-slider-root, fs-radio-group, fs-switch-root, fs-checkbox-group',
      )!,
    ]),
  ) as Record<keyof FormValues, HTMLElement>;
  const errors = Object.fromEntries(fieldNames.map(name => [name, fields[name].querySelector('fs-field-error')])) as Record<
    keyof FormValues,
    (HTMLElement & Components.FsFieldError) | null
  >;
  const toastViewport = content.querySelector('fs-toast-viewport')!;
  container.append(content);
  return { provider, form, fields, controls, errors, toastViewport, destroy: () => provider.remove() };
}
export type FormElements = ReturnType<typeof createForm>;
```

```tsx
/* button.tsx */
import * as React from 'react';
import { Button as BaseButton } from '@base-ui/react/button';
import clsx from 'clsx';

export function Button({ className, ...props }: React.ComponentPropsWithoutRef<'button'>) {
  return (
    <BaseButton
      type="button"
      className={clsx(
        'flex h-8 items-center justify-center gap-2 rounded-none border border-neutral-950 bg-white px-3 py-0 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 disabled:border-neutral-500 disabled:text-neutral-500 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:disabled:border-neutral-400 dark:disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';

export function CheckboxGroup({ className, ...props }: BaseCheckboxGroup.Props) {
  return <BaseCheckboxGroup className={clsx('flex flex-col items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* form.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Form as BaseForm } from '@base-ui/react/form';

export function Form({ className, ...props }: BaseForm.Props) {
  return <BaseForm className={clsx('flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]', className)} {...props} />;
}
```

```tsx
/* radio-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';

export function RadioGroup<Value>({ className, ...props }: BaseRadioGroup.Props<Value>) {
  return <BaseRadioGroup className={clsx('flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* toast.tsx */
'use client';
import * as React from 'react';
import { Toast } from '@base-ui/react/toast';

function Toasts() {
  const { toasts } = Toast.useToastManager();
  return toasts.map(toast => (
    <Toast.Root
      key={toast.id}
      toast={toast}
      className="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]"
    >
      <Toast.Content className="h-full overflow-hidden p-3 transition-opacity duration-250">
        <Toast.Title className="text-sm font-bold" />
        <Toast.Description className="text-sm text-neutral-700 dark:text-neutral-300" />
        <div className="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore>
          <pre className="whitespace-pre-wrap">{JSON.stringify(toast.data, null, 2)}</pre>
        </div>
        <Toast.Close
          className="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700"
          aria-label="Close"
        >
          <XIcon />
        </Toast.Close>
      </Toast.Content>
    </Toast.Root>
  ));
}

export function ToastProvider(props: { children: React.ReactNode }) {
  return (
    <Toast.Provider limit={1}>
      {props.children}
      <Toast.Portal>
        <Toast.Viewport className="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]">
          <Toasts />
        </Toast.Viewport>
      </Toast.Portal>
    </Toast.Provider>
  );
}

export const useToastManager = Toast.useToastManager;

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m2.5 2.5 11 11m-11 0 11-11" />
    </svg>
  );
}
```

```tsx
/* autocomplete.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Autocomplete } from '@base-ui/react/autocomplete';

export function Root(props: Autocomplete.Root.Props<any>) {
  return <Autocomplete.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Autocomplete.Input.Props>(function Input(
  { className, ...props }: Autocomplete.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Autocomplete.Input
      ref={forwardedRef}
      className={clsx(
        'h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Portal(props: Autocomplete.Portal.Props) {
  return <Autocomplete.Portal {...props} />;
}

export function Positioner({ className, ...props }: Autocomplete.Positioner.Props) {
  return <Autocomplete.Positioner className={clsx('outline-none data-empty:hidden', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Autocomplete.Popup.Props) {
  return (
    <Autocomplete.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Autocomplete.List.Props) {
  return (
    <Autocomplete.List
      className={clsx('max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Autocomplete.Item.Props) {
  return (
    <Autocomplete.Item
      className={clsx(
        'flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Checkbox } from '@base-ui/react/checkbox';

export function Root({ className, ...props }: Checkbox.Root.Props) {
  return (
    <Checkbox.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Checkbox.Indicator.Props) {
  return <Checkbox.Indicator className={clsx('flex data-unchecked:hidden', className)} {...props} />;
}
```

```tsx
/* combobox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Combobox } from '@base-ui/react/combobox';

export function Root(props: Combobox.Root.Props<any, any>) {
  return <Combobox.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Combobox.Input.Props>(function Input(
  { className, ...props }: Combobox.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Combobox.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function InputGroup({ className, ...props }: Combobox.InputGroup.Props) {
  return (
    <Combobox.InputGroup
      className={clsx(
        'relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>input]:pr-[2.5rem] has-[.combobox-clear]:[&>input]:pr-[calc(0.5rem+2rem*2)]',
        className,
      )}
      {...props}
    />
  );
}

export function Clear({ className, ...props }: Combobox.Clear.Props) {
  return (
    <Combobox.Clear
      className={clsx('combobox-clear flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)}
      {...props}
    >
      <XIcon />
    </Combobox.Clear>
  );
}

export function Trigger({ className, ...props }: Combobox.Trigger.Props) {
  return <Combobox.Trigger className={clsx('flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Portal(props: Combobox.Portal.Props) {
  return <Combobox.Portal {...props} />;
}

export function Positioner({ className, ...props }: Combobox.Positioner.Props) {
  return <Combobox.Positioner className={clsx('outline-none', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Combobox.Popup.Props) {
  return (
    <Combobox.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function Empty({ className, children, ...props }: Combobox.Empty.Props) {
  return (
    <Combobox.Empty {...props}>
      {children ? <div className={clsx('py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400', className)}>{children}</div> : null}
    </Combobox.Empty>
  );
}

export function List({ className, ...props }: Combobox.List.Props) {
  return (
    <Combobox.List
      className={clsx('outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Combobox.Item.Props) {
  return (
    <Combobox.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Combobox.ItemIndicator.Props) {
  return <Combobox.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function CaretDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M12 6H4l4 4.5z" />
    </svg>
  );
}

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m4.5 4.5 7 7m-7 0 7-7" />
    </svg>
  );
}
```

```tsx
/* field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Field } from '@base-ui/react/field';

export function Root({ className, ...props }: Field.Root.Props) {
  return <Field.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Label({ className, ...props }: Field.Label.Props) {
  return (
    <Field.Label
      className={clsx(
        'text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white',
        className,
      )}
      {...props}
    />
  );
}

export function Description({ className, ...props }: Field.Description.Props) {
  return <Field.Description className={clsx('text-sm text-neutral-600 dark:text-neutral-400', className)} {...props} />;
}

export const Control = React.forwardRef<HTMLInputElement, Field.Control.Props>(function FieldControl(
  { className, ...props }: Field.Control.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Field.Control
      ref={forwardedRef}
      className={clsx(
        'h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Error({ className, ...props }: Field.Error.Props) {
  return <Field.Error className={clsx('text-sm text-red-700 dark:text-red-400', className)} {...props} />;
}

export function Item(props: Field.Item.Props) {
  return <Field.Item {...props} />;
}
```

```tsx
/* fieldset.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Fieldset } from '@base-ui/react/fieldset';

export function Root(props: Fieldset.Root.Props) {
  return <Fieldset.Root {...props} />;
}

export function Legend({ className, ...props }: Fieldset.Legend.Props) {
  return <Fieldset.Legend className={clsx('text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* number-field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { NumberField } from '@base-ui/react/number-field';

export function Root({ className, ...props }: NumberField.Root.Props) {
  return <NumberField.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Group({ className, ...props }: NumberField.Group.Props) {
  return <NumberField.Group className={clsx('flex h-8', className)} {...props} />;
}

export function Decrement({ className, ...props }: NumberField.Decrement.Props) {
  return (
    <NumberField.Decrement
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}

export const Input = React.forwardRef<HTMLInputElement, NumberField.Input.Props>(function Input(
  { className, ...props }: NumberField.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <NumberField.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white',
        className,
      )}
      {...props}
    />
  );
});

export function Increment({ className, ...props }: NumberField.Increment.Props) {
  return (
    <NumberField.Increment
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* radio.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Radio } from '@base-ui/react/radio';

export function Root({ className, ...props }: Radio.Root.Props) {
  return (
    <Radio.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Radio.Indicator.Props) {
  return <Radio.Indicator className={clsx('flex items-center justify-center data-unchecked:hidden before:size-2 before:rounded-full before:bg-current', className)} {...props} />;
}
```

```tsx
/* select.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Select } from '@base-ui/react/select';

export function Root(props: Select.Root.Props<any>) {
  return <Select.Root {...props} />;
}

export function Label({ className, ...props }: Select.Label.Props) {
  return <Select.Label className={clsx('cursor-default text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Trigger({ className, ...props }: Select.Trigger.Props) {
  return (
    <Select.Trigger
      className={clsx(
        'flex h-8 min-w-40 cursor-default items-center justify-between gap-3 border border-neutral-950 bg-white pl-2 pr-1 text-sm font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 data-pressed:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:data-pressed:bg-neutral-800',
        className,
      )}
      {...props}
    />
  );
}

export function Value({ className, ...props }: Select.Value.Props) {
  return <Select.Value className={clsx('data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400', className)} {...props} />;
}

export function Icon(props: Select.Icon.Props) {
  return <Select.Icon {...props} />;
}

export function Portal(props: Select.Portal.Props) {
  return <Select.Portal {...props} />;
}

export function Positioner({ className, ...props }: Select.Positioner.Props) {
  return <Select.Positioner className={clsx('outline-none select-none z-10', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Select.Popup.Props) {
  return (
    <Select.Popup
      className={clsx(
        'group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function ScrollUpArrow({ className, ...props }: Select.ScrollUpArrow.Props) {
  return (
    <Select.ScrollUpArrow
      className={clsx(
        "top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function ScrollDownArrow({ className, ...props }: Select.ScrollDownArrow.Props) {
  return (
    <Select.ScrollDownArrow
      className={clsx(
        "bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Select.List.Props) {
  return <Select.List className={clsx('relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6', className)} {...props} />;
}

export function Item({ className, ...props }: Select.Item.Props) {
  return (
    <Select.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Select.ItemIndicator.Props) {
  return <Select.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function ItemText({ className, ...props }: Select.ItemText.Props) {
  return <Select.ItemText className={clsx('col-start-2', className)} {...props} />;
}
```

```tsx
/* slider.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Slider } from '@base-ui/react/slider';

export function Root({ className, ...props }: Slider.Root.Props<any>) {
  return <Slider.Root className={clsx('grid grid-cols-2', className)} {...props} />;
}

export function Value({ className, ...props }: Slider.Value.Props) {
  return <Slider.Value className={clsx('text-sm font-normal text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Control({ className, ...props }: Slider.Control.Props) {
  return <Slider.Control className={clsx('flex col-span-2 touch-none items-center py-3 select-none', className)} {...props} />;
}

export function Track({ className, ...props }: Slider.Track.Props) {
  return <Slider.Track className={clsx('h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800', className)} {...props} />;
}

export function Indicator({ className, ...props }: Slider.Indicator.Props) {
  return <Slider.Indicator className={clsx('bg-neutral-950 select-none dark:bg-white', className)} {...props} />;
}

export function Thumb({ className, ...props }: Slider.Thumb.Props) {
  return (
    <Slider.Thumb
      className={clsx(
        'size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* switch.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Switch } from '@base-ui/react/switch';

export function Root({ className, ...props }: Switch.Root.Props) {
  return (
    <Switch.Root
      className={clsx(
        'flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function Thumb({ className, ...props }: Switch.Thumb.Props) {
  return (
    <Switch.Thumb
      className={clsx(
        'size-3.5 bg-neutral-950 transition-[translate,background-color] duration-150 ease-[ease] data-checked:translate-x-4 data-checked:bg-white dark:bg-white dark:data-checked:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```ts
/* stencil-hero.ts */
import { createForm } from './stencil-form';
import { connectToasts } from './stencil-toast';

export function mount(container: HTMLElement, themed = false) {
  const elements = createForm(container, { themed });
  const toasts = connectToasts(elements.provider, elements.toastViewport, themed);
  elements.form.formSubmit = values => toasts.submit(values);
  return () => {
    toasts.destroy();
    elements.destroy();
  };
}
```

```ts
/* stencil-toast.ts */
import { createToastManager, type ToastObject } from 'finesoft-components/toast';
import type { Components } from 'finesoft-components';

const toastHTML = `
<fs-toast-root class="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]">
  <fs-toast-content class="h-full overflow-hidden p-3 transition-opacity duration-250">
    <fs-toast-title class="text-sm font-bold"></fs-toast-title>
    <fs-toast-description class="text-sm text-neutral-700 dark:text-neutral-300"></fs-toast-description>
    <div class="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore="true">
      <pre class="whitespace-pre-wrap"></pre>
    </div>
    <fs-toast-close class="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700" aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

const themedToastHTML = `
<fs-toast-root data-fs-variant="rich">
  <fs-toast-content>
    <fs-toast-title></fs-toast-title>
    <fs-toast-description></fs-toast-description>
    <div class="handbook-form-submitted-values" data-base-ui-swipe-ignore="true">
      <pre></pre>
    </div>
    <fs-toast-close aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

export function connectToasts(provider: HTMLElement & Components.FsToastProvider, viewport: Element, themed = false) {
  const manager = createToastManager();
  const roots = new Map<string, HTMLElement & Components.FsToastRoot>();
  function update(event: CustomEvent<ToastObject[]>) {
    const toasts = event.detail;
    for (const [id, root] of roots) {
      if (!toasts.some(toast => toast.id === id)) {
        root.remove();
        roots.delete(id);
      }
    }
    for (const toast of toasts) {
      let root = roots.get(toast.id);
      if (!root) {
        const template = provider.ownerDocument.createElement('template');
        template.innerHTML = themed ? themedToastHTML : toastHTML;
        root = template.content.firstElementChild as HTMLElement & Components.FsToastRoot;
        root.toast = toast;
        root.querySelector('pre')!.textContent = JSON.stringify(toast.data, null, 2);
        roots.set(toast.id, root);
        viewport.append(root);
      } else {
        root.toast = toast;
      }
    }
  }
  provider.addEventListener('toastsChange', update as EventListener);
  provider.toastManager = manager;
  return {
    submit: (data: unknown) => manager.add({ title: 'Form submitted', description: 'The form contains these values:', data: data as Record<string, unknown> }),
    destroy: () => provider.removeEventListener('toastsChange', update as EventListener),
  };
}
```

Each runnable example below includes a FineSoft Stencil version. Open `stencil-form.ts` to see the actual `<fs-form>`, `<fs-field-root>`, `<fs-combobox-root>` and other Web Components tags used by all three examples. The native example uses `formSubmit`; TanStack Form uses its framework-independent core. React Hook Form retains only the React integration required by that library. Their visible event bindings exchange values through public properties and `CustomEvent.detail`; there are no React wrappers for the Stencil components. To run a native example, register `defineCustomElements()` from `finesoft-components/define-custom-elements`, then call its exported `mount(container)` function. Use its returned cleanup function on removal.

## Naming form controls

Form controls must have an accessible name in order to be recognized by assistive technologies. Use the label strategy below for each control type.

### Input controls

Use `<Field.Label>` or a native `<label>` to label the following controls:

- `Input`
- `NumberField`
- `OTPField`
- `Autocomplete`
- `Combobox` (input outside popup)
- `Checkbox`
- `Radio`
- `Switch`

You can implicitly label `<Checkbox>`, `<Radio>` and `<Switch>` components by enclosing them with `<Field.Label>`:

```tsx title="Implicitly labeling a switch"
import { Field } from '@base-ui/react/field';
import { Switch } from '@base-ui/react/switch';

<Field.Root>
  <Field.Label>
    <Switch.Root />
    Developer mode
  </Field.Label>
  <Field.Description>Enables extra tools for web developers</Field.Description>
</Field.Root>;
```

### Trigger-based controls

- `Combobox` (input inside popup): use `<Combobox.Label>`.
- `Select`: use `<Select.Label>`.
- `Slider`: use `<Slider.Label>`. For multi-thumb sliders, also add an `aria-label` on each
  `<Slider.Thumb>` to distinguish the thumbs.

### Fallback

If no visible label is rendered, provide `aria-label` on the actual form control.

### Describing the control

`<Field.Description>` automatically assigns an accessible description:

```tsx title="Labeling select and slider"
import { Form } from '@base-ui/react/form';
import { Field } from '@base-ui/react/field';
import { Select } from '@base-ui/react/select';
import { Slider } from '@base-ui/react/slider';

<Form>
  <Field.Root>
    <Select.Root>
      <Select.Label>Time zone</Select.Label>
      <Select.Trigger />
    </Select.Root>
    <Field.Description>Used for notifications and reminders</Field.Description>
  </Field.Root>

  <Field.Root>
    <Slider.Root defaultValue={50}>
      <Slider.Label>Zoom level</Slider.Label>
      <Field.Description>Adjust the size of the user interface</Field.Description>
      <Slider.Control>
        <Slider.Track>
          <Slider.Thumb />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  </Field.Root>
</Form>;
```

### Labeling control groups

Compose `<Fieldset>` when a single label applies to multiple controls, such as a range slider with multiple thumbs or a section that combines several inputs. For checkbox and radio groups, keep the group label in `<Fieldset.Legend>` and wrap each option with `<Field.Item>`:

```tsx title="Composing range slider and radio group with fieldset"
import { Form } from '@base-ui/react/form';
import { Field } from '@base-ui/react/field';
import { Fieldset } from '@base-ui/react/fieldset';
import { Radio } from '@base-ui/react/radio';
import { RadioGroup } from '@base-ui/react/radio-group';
import { Slider } from '@base-ui/react/slider';

<Form>
  <Field.Root>
    {/* @highlight-start */}
    <Fieldset.Root render={<Slider.Root />}>
      <Fieldset.Legend>Price range</Fieldset.Legend>
      {/* @highlight-end */}
      <Slider.Control>
        <Slider.Track>
          <Slider.Thumb aria-label="Minimum price" />
          <Slider.Thumb aria-label="Maximum price" />
        </Slider.Track>
      </Slider.Control>
      {/* @highlight */}
    </Fieldset.Root>
  </Field.Root>

  <Field.Root>
    {/* @highlight-start */}
    <Fieldset.Root render={<RadioGroup />}>
      <Fieldset.Legend>Storage type</Fieldset.Legend>
      {/* @highlight-end */}
      <Radio.Root value="ssd" />
      <Radio.Root value="hdd" />
      {/* @highlight */}
    </Fieldset.Root>
  </Field.Root>
</Form>;
```

`<Field.Item>` should enclose each checkbox or radio option so every control has its own label and description:

```tsx title="Explicitly labeling checkboxes in a checkbox group"
import { Form } from '@base-ui/react/form';
import { Field } from '@base-ui/react/field';
import { Fieldset } from '@base-ui/react/fieldset';
import { Checkbox } from '@base-ui/react/checkbox';
import { CheckboxGroup } from '@base-ui/react/checkbox-group';

<Field.Root>
  <Fieldset.Root render={<CheckboxGroup />}>
    <Fieldset.Legend>Backup schedule</Fieldset.Legend>
    {/* @highlight */}
    <Field.Item>
      <Checkbox.Root value="daily" />
      <Field.Label>Daily</Field.Label>
      <Field.Description>Daily at 00:00</Field.Description>
      {/* @highlight-start */}
    </Field.Item>
    <Field.Item>
      {/* @highlight-end */}
      <Checkbox.Root value="monthly" />
      <Field.Label>Monthly</Field.Label>
      <Field.Description>On the 5th of every month at 23:59</Field.Description>
      {/* @highlight */}
    </Field.Item>
  </Fieldset.Root>
</Field.Root>;
```

## Building form fields

Pass the `name` prop to `<Field.Root>` to include the wrapped control's value when a parent form is submitted:

```tsx title="Assigning field name to combobox"
import { Form } from '@base-ui/react/form';
import { Field } from '@base-ui/react/field';
import { Combobox } from '@base-ui/react/combobox';

<Form>
  {/* @highlight-start */}
  {/* @highlight-text "name" */}
  <Field.Root name="country">
    {/* @highlight-end */}
    <Field.Label>Country of residence</Field.Label>
    <Combobox.Root />
  </Field.Root>
</Form>;
```

## Submitting data

You can take over form submission using the native `onSubmit`, or custom `onFormSubmit` props:

```tsx title="Native submission using onSubmit"
import { Form } from '@base-ui/react/form';

<Form
  // @highlight-start
  onSubmit={async event => {
    // Prevent the browser's default full-page refresh
    event.preventDefault();
    // Create a FormData object
    const formData = new FormData(event.currentTarget);
    // Send the FormData instance in a fetch request
    // @highlight-end
    await fetch('https://api.example.com', {
      method: 'POST',
      body: formData,
    });
  }}
/>;
```

When using `onFormSubmit`, you receive form values as a JavaScript object, with `eventDetails` provided as a second argument. Additionally, `preventDefault()` is automatically called on the native submit event:

```tsx title="Submission using onFormSubmit"
import { Form } from '@base-ui/react/form';

<Form
  // @highlight-start
  onFormSubmit={async formValues => {
    const payload = {
      product_id: formValues.id,
      order_quantity: formValues.quantity,
    };
    await fetch('https://api.example.com', {
      // @highlight-end
      method: 'POST',
      body: JSON.stringify(payload),
    });
  }}
/>;
```

## Constraint validation

Base UI form components support native HTML validation attributes for many validation rules:

- `required` specifies a required field.
- `minLength` and `maxLength` specify a valid length for text fields.
- `pattern` specifies a regular expression that the field value must match.
- `step` specifies an increment that numeric field values must be an integral multiple of.

```tsx title="Defining constraint validation on a text field"
import { Field } from '@base-ui/react/field';

<Field.Root name="website">
  <Field.Control type="url" required pattern="https?://.*" />
  <Field.Error />
</Field.Root>;
```

Base UI form components use a hidden input to participate in native form submission and validation.
To anchor the hidden input near a control so the native validation bubble points to the correct area, ensure the component has been given a `name`, and wrap controls in a relatively positioned container for best results.

```tsx title="Positioning hidden inputs"
import { Field } from '@base-ui/react/field';
import { Select } from '@base-ui/react/select';

<Field.Root name="apple">
  <Select.Root>
    <Select.Label>Apple</Select.Label>
    <div className="relative">
      <Select.Trigger />
    </div>
  </Select.Root>
</Field.Root>;
```

## Custom validation

You can add custom validation logic by passing a synchronous or asynchronous validation function to the `validate` prop, which runs after native validations have passed.

Use the `validationMode` prop to configure when validation is performed:

- `onSubmit` (default) validates all fields when the containing `<Form>` is submitted, afterwards invalid fields revalidate when their value changes.
- `onBlur` validates the field when focus moves away.
- `onChange` validates the field when the value changes, for example, after each keypress in a text field or when a checkbox is checked or unchecked.

`validationDebounceTime` can be used to debounce the function in use cases such as asynchronous requests or text fields that validate `onChange`.

```tsx title="Text input using custom asynchronous validation"
import { Field } from '@base-ui/react/field';

<Field.Root
  name="username"
  {/* @highlight-start */}
  validationMode="onChange"
  validationDebounceTime={300}
  validate={async (value) => {
  // @highlight-end
    if (value === 'admin') {
      /* return an error message when invalid */
      return 'Reserved for system use.';
    }

    const result = await fetch(
      {/* prettier-ignore */},
      /* check the availability of a username from an external API */
    );

    if (!result) {
      return `${value} is unavailable.`;
    }

    /* return `null` when valid */
    return null;
  }}
>
  <Field.Control required minLength={3} />
  <Field.Error />
</Field.Root>;
```

## Server-side validation

You can pass errors returned by (post-submission) server-side validation to the `errors` prop, which will be merged into the client-side field state for display.

This should be an object with field names as keys, and an error string or array of strings as the value. Once a field's value changes, any corresponding error in `errors` will be cleared from the field state.

```tsx title="Displaying errors returned by server-side validation"
import { Form } from '@base-ui/react/form';
import { Field } from '@base-ui/react/field';

async function submitToServer(/* payload */) {
  return {
    errors: { {// @highlight-text "errors"
      promoCode: 'This promo code has expired',
    },
  };
}

const [errors, setErrors] = React.useState(); // @highlight-text "errors"

<Form
  errors={errors} { // @highlight-text "errors"
  onSubmit={async (event) => {
    event.preventDefault();
    const response = await submitToServer(/* data */);
    setErrors(response.errors); // @highlight-text "errors"
  }}
>
  <Field.Root name="promoCode" />
</Form>;
```

When using [Server Functions with Form Actions](https://react.dev/reference/rsc/server-functions#server-functions-with-use-action-state) you can return server-side errors from `useActionState` to the `errors` prop. A demo is available [here](/react/components/form.md).

```tsx title="Returning errors from useActionState"
// app/form.tsx
/* prettier-ignore */
'use client';
import { Form } from '@base-ui/react/form';
import { Field } from '@base-ui/react/field';
import { login } from './actions';

// @highlight-text "state" "formAction"
const [state, formAction, loading] = React.useActionState(login, {});

// @highlight-text "state" "errors" "formAction"
<Form action={formAction} errors={state.errors}>
  <Field.Root name="password">
    <Field.Control />
    <Field.Error />
  </Field.Root>
</Form>;

// app/actions.ts
/* prettier-ignore */
'use server';
export async function login(formData: FormData) {
  const result = authenticateUser(formData);

  if (!result.success) {
    return {
      // @highlight-text "errors"
      errors: {
        password: 'Invalid username or password',
      },
    };
  }
  /* redirect on the server on success */
}
```

## Displaying errors

Use `<Field.Error>` without `children` to automatically display the field's native error message when invalid. The `match` prop can be used to customize the message based on the validity state, and manage internationalization from your application logic:

```tsx title="Customizing error message for a required field"
<Field.Error match="valueMissing">You must create a username</Field.Error>
```

## React Hook Form

[React Hook Form](https://react-hook-form.com) is a popular library that you can integrate with Base UI to externally manage form and field state for your existing components.

## Demo

### Component theme

The Stencil example uses the built-in component theme. The frozen React comparison retains its original Tailwind styling.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactExample from './react-react-hook-form';
import StencilExample from './stencil-themed-react-hook-form';
import { formHTML, configureForm } from './stencil-form';

export default function Comparison() {
  const options = { themed: true, externalValidation: true };
  return (
    <StencilComparison
      component="handbook-form-react-hook-form"
      react={<ReactExample />}
      stencil={null}
      renderSource={() => formHTML(options)}
      beforeHydrate={document => configureForm(document, options)}
      clientStencil={<StencilExample />}
    />
  );
}
```

```tsx
/* react-react-hook-form.tsx */
'use client';
import * as React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { Button } from './button';
import { CheckboxGroup } from './checkbox-group';
import { Form } from './form';
import { RadioGroup } from './radio-group';
import { ToastProvider, useToastManager } from './toast';
import * as Autocomplete from './autocomplete';
import * as Checkbox from './checkbox';
import * as Combobox from './combobox';
import * as Field from './field';
import * as Fieldset from './fieldset';
import * as NumberField from './number-field';
import * as Radio from './radio';
import * as Select from './select';
import * as Slider from './slider';
import * as Switch from './switch';

interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

function ReactHookForm() {
  const toastManager = useToastManager();

  const { control, handleSubmit } = useForm<FormValues>({
    defaultValues: {
      serverName: '',
      region: null,
      containerImage: '',
      serverType: null,
      numOfInstances: null,
      scalingThreshold: [0.2, 0.8],
      storageType: 'ssd',
      restartOnFailure: true,
      allowedNetworkProtocols: [],
    },
  });

  function submitForm(data: FormValues) {
    toastManager.add({
      title: 'Form submitted',
      description: 'The form contains these values:',
      data,
    });
  }

  return (
    <Form aria-label="Launch new cloud server" onSubmit={handleSubmit(submitForm)}>
      <Controller
        name="serverName"
        control={control}
        rules={{
          required: 'This field is required.',
          minLength: { value: 3, message: 'At least 3 characters.' },
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Field.Label>Server name</Field.Label>
            <Field.Control ref={ref} value={value} onBlur={onBlur} onValueChange={onChange} placeholder="e.g. api-server-01" />
            <Field.Description>Must be 3 or more characters long</Field.Description>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="region"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Combobox.Root items={REGIONS} value={value} onValueChange={onChange}>
              <div className="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
                <Field.Label className="mb-1 block">Region</Field.Label>
                <Combobox.InputGroup>
                  <Combobox.Input placeholder="e.g. eu-central-1" ref={ref} onBlur={onBlur} />
                  <div className="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
                    <Combobox.Clear />
                    <Combobox.Trigger>
                      <Combobox.CaretDownIcon />
                    </Combobox.Trigger>
                  </div>
                </Combobox.InputGroup>
              </div>
              <Combobox.Portal>
                <Combobox.Positioner>
                  <Combobox.Popup>
                    <Combobox.Empty>No matches</Combobox.Empty>
                    <Combobox.List>
                      {(region: string) => {
                        return (
                          <Combobox.Item key={region} value={region}>
                            <Combobox.ItemIndicator>
                              <CheckIcon />
                            </Combobox.ItemIndicator>
                            <span className="col-start-2">{region}</span>
                          </Combobox.Item>
                        );
                      }}
                    </Combobox.List>
                  </Combobox.Popup>
                </Combobox.Positioner>
              </Combobox.Portal>
            </Combobox.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="containerImage"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Autocomplete.Root items={IMAGES} mode="both" itemToStringValue={(itemValue: Image) => itemValue.url} value={value} onValueChange={onChange}>
              <Field.Label>Container image</Field.Label>
              <Autocomplete.Input placeholder="e.g. docker.io/library/node:latest" ref={ref} onBlur={onBlur} />
              <Field.Description>Enter a registry URL with optional tags</Field.Description>
              <Autocomplete.Portal>
                <Autocomplete.Positioner>
                  <Autocomplete.Popup>
                    <Autocomplete.List>
                      {(image: Image) => {
                        return (
                          <Autocomplete.Item key={image.url} value={image}>
                            <span>{image.name}</span>
                            <span className="font-mono whitespace-nowrap text-xs opacity-80">{image.url}</span>
                          </Autocomplete.Item>
                        );
                      }}
                    </Autocomplete.List>
                  </Autocomplete.Popup>
                </Autocomplete.Positioner>
              </Autocomplete.Portal>
            </Autocomplete.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="serverType"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Select.Root items={SERVER_TYPES} value={value} onValueChange={onChange} inputRef={ref}>
              <div className="w-fit space-y-1">
                <Select.Label>Server type</Select.Label>
                <Select.Trigger className="w-48" onBlur={onBlur}>
                  <Select.Value />
                  <Select.Icon>
                    <CaretUpDownIcon />
                  </Select.Icon>
                </Select.Trigger>
              </div>
              <Select.Portal>
                <Select.Positioner>
                  <Select.Popup>
                    <Select.ScrollUpArrow />
                    <Select.List>
                      {SERVER_TYPES.map(({ label, value: serverType }) => {
                        return (
                          <Select.Item key={serverType} value={serverType}>
                            <Select.ItemIndicator>
                              <CheckIcon />
                            </Select.ItemIndicator>
                            <Select.ItemText>{label}</Select.ItemText>
                          </Select.Item>
                        );
                      })}
                    </Select.List>
                    <Select.ScrollDownArrow />
                  </Select.Popup>
                </Select.Positioner>
              </Select.Portal>
            </Select.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="numOfInstances"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <NumberField.Root value={value} min={1} max={64} onValueChange={onChange}>
              <Field.Label>Number of instances</Field.Label>
              <NumberField.Group>
                <NumberField.Decrement>
                  <MinusIcon />
                </NumberField.Decrement>
                <NumberField.Input ref={ref} onBlur={onBlur} />
                <NumberField.Increment>
                  <PlusIcon />
                </NumberField.Increment>
              </NumberField.Group>
            </NumberField.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="scalingThreshold"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Fieldset.Root
              render={
                <Slider.Root
                  value={value}
                  onValueChange={onChange}
                  onValueCommitted={onChange}
                  thumbAlignment="edge"
                  min={0}
                  max={1}
                  step={0.01}
                  format={{
                    style: 'percent',
                    minimumFractionDigits: 0,
                    maximumFractionDigits: 0,
                  }}
                  className="w-full gap-y-2"
                />
              }
            >
              <Fieldset.Legend>Scaling threshold</Fieldset.Legend>
              <Slider.Value className="col-start-2 text-end" />
              <Slider.Control>
                <Slider.Track>
                  <Slider.Indicator />
                  <Slider.Thumb index={0} aria-label="Minimum threshold" onBlur={onBlur} inputRef={ref} />
                  <Slider.Thumb index={1} aria-label="Maximum threshold" onBlur={onBlur} />
                </Slider.Track>
              </Slider.Control>
            </Fieldset.Root>
          </Field.Root>
        )}
      />

      <Controller
        name="storageType"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Fieldset.Root render={<RadioGroup className="gap-4" value={value} onValueChange={onChange} inputRef={ref} />}>
              <Fieldset.Legend className="-mt-px">Storage type</Fieldset.Legend>
              <Field.Item>
                <Field.Label>
                  <Radio.Root value="ssd" onBlur={onBlur}>
                    <Radio.Indicator />
                  </Radio.Root>
                  SSD
                </Field.Label>
              </Field.Item>
              <Field.Item>
                <Field.Label>
                  <Radio.Root value="hdd" onBlur={onBlur}>
                    <Radio.Indicator />
                  </Radio.Root>
                  HDD
                </Field.Label>
              </Field.Item>
            </Fieldset.Root>
          </Field.Root>
        )}
      />

      <Controller
        name="restartOnFailure"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Field.Label className="gap-2">
              Restart on failure
              <Switch.Root checked={value} inputRef={ref} onCheckedChange={onChange} onBlur={onBlur}>
                <Switch.Thumb />
              </Switch.Root>
            </Field.Label>
          </Field.Root>
        )}
      />

      <Controller
        name="allowedNetworkProtocols"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Fieldset.Root render={<CheckboxGroup value={value} onValueChange={onChange} />}>
              <Fieldset.Legend className="mb-2">Allowed network protocols</Fieldset.Legend>
              <div className="flex gap-4">
                {['http', 'https', 'ssh'].map(val => {
                  return (
                    <Field.Item key={val}>
                      <Field.Label className="uppercase">
                        <Checkbox.Root value={val} inputRef={val === 'http' ? ref : undefined} onBlur={onBlur}>
                          <Checkbox.Indicator>
                            <CheckIcon />
                          </Checkbox.Indicator>
                        </Checkbox.Root>
                        {val}
                      </Field.Label>
                    </Field.Item>
                  );
                })}
              </div>
            </Fieldset.Root>
          </Field.Root>
        )}
      />

      <Button type="submit" className="mt-3">
        Launch server
      </Button>
    </Form>
  );
}

export default function App() {
  return (
    <ToastProvider>
      <ReactHookForm />
    </ToastProvider>
  );
}

function CaretUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="m2.5 8.5 4 4 7-9" />
    </svg>
  );
}

function PlusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13M8 14.5v-13" />
    </svg>
  );
}

function MinusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13" />
    </svg>
  );
}

function cartesian<T extends string[][]>(...arrays: T): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}

const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));

interface Image {
  url: string;
  name: string;
}
/* prettier-ignore */
const IMAGES: Image[] = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map((name) => ({
  url: `docker.io/library/${name}`,
  name,
}));

const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];
```

```tsx
/* stencil-themed-react-hook-form.tsx */
'use client';
import Form from './stencil-react-hook-form';
import './stencil-form.css';

export default function StencilReactHookForm() {
  return <Form themed />;
}
```

```ts
/* stencil-form.ts */
import type { Components } from 'finesoft-components';

export interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

export const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};
export const fieldNames = Object.keys(defaultValues) as Array<keyof FormValues>;
export interface FormOptions {
  externalValidation?: boolean;
  nativeForm?: boolean;
  themed?: boolean;
}

function cartesian(...arrays: string[][]): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}
const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));
const IMAGES = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map(name => ({ name, url: `docker.io/library/${name}` }));
const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];

// This same Web Components declaration is used by the browser and by Stencil SSR.
// The framework integrations below only exchange public properties and events.
export function formHTML(options: FormOptions = {}): string {
  if (options.themed) return themedFormHTML(options);
  const { nativeForm = false } = options;
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]" aria-label="Launch new cloud server">
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverName">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Server name</fs-field-label>
      <fs-field-control class="h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Must be 3 or more characters long</fs-field-description>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="region">
      <fs-combobox-root required="">
        <div class="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
          <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white mb-1 block'>Region</fs-field-label>
          <fs-combobox-input-group class="relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>fs-combobox-input>input]:pr-[2.5rem] has-[.combobox-clear]:[&>fs-combobox-input>input]:pr-[calc(0.5rem+2rem*2)]">
            <fs-combobox-input class="h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div class="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
              <fs-combobox-clear class="[&::part(clear)]:box-border [&::part(clear)]:m-0 [&::part(clear)]:p-0 [&::part(clear)]:border-solid [&::part(clear)]:[font-family:inherit] [&::part(clear)]:[font-size:inherit] [&::part(clear)]:[font-weight:inherit] [&::part(clear)]:[line-height:inherit] combobox-clear [&::part(clear)]:flex [&::part(clear)]:h-full [&::part(clear)]:w-6 [&::part(clear)]:items-center [&::part(clear)]:justify-center [&::part(clear)]:border-0 [&::part(clear)]:bg-transparent [&::part(clear)]:p-0 [&::part(clear)]:text-neutral-950 dark:[&::part(clear)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:p-0 [&::part(trigger)]:border-solid [&::part(trigger)]:[font-family:inherit] [&::part(trigger)]:[font-size:inherit] [&::part(trigger)]:[font-weight:inherit] [&::part(trigger)]:[line-height:inherit] [&::part(trigger)]:flex [&::part(trigger)]:h-full [&::part(trigger)]:w-6 [&::part(trigger)]:items-center [&::part(trigger)]:justify-center [&::part(trigger)]:border-0 [&::part(trigger)]:bg-transparent [&::part(trigger)]:p-0 [&::part(trigger)]:text-neutral-950 dark:[&::part(trigger)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner class="outline-none" side-offset="4">
            <fs-combobox-popup class="w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-combobox-empty>
                <div class="py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400">No matches</div>
              </fs-combobox-empty>
              <fs-combobox-list class="outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0">${REGIONS.map(
                region => `
<fs-combobox-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white" value="${region}">
  <fs-combobox-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span class="col-start-2">${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Container image</fs-field-label>
        <fs-autocomplete-input class="h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner class="outline-none data-empty:hidden" side-offset="4">
            <fs-autocomplete-popup class="w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-autocomplete-list class="max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0">${IMAGES.map(
                image => `
<fs-autocomplete-item class="flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white">
  <span>${image.name}</span>
  <span class="font-mono whitespace-nowrap text-xs opacity-80">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverType">
      <fs-select-root required="">
        <div class="w-fit space-y-1">
          <fs-select-label class="cursor-default text-sm font-bold text-neutral-950 dark:text-white">Server type</fs-select-label>
          <fs-select-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:font-[inherit] [&::part(trigger)]:border-solid [&::part(trigger)]:p-0 [&::part(trigger)]:flex [&::part(trigger)]:h-8 [&::part(trigger)]:min-w-40 [&::part(trigger)]:cursor-default [&::part(trigger)]:items-center [&::part(trigger)]:justify-between [&::part(trigger)]:gap-3 [&::part(trigger)]:border [&::part(trigger)]:border-neutral-950 [&::part(trigger)]:bg-white [&::part(trigger)]:pl-2 [&::part(trigger)]:pr-1 [&::part(trigger)]:text-sm [&::part(trigger)]:font-normal [&::part(trigger)]:text-neutral-950 [&::part(trigger)]:select-none not-data-disabled:[&::part(trigger)]:hover:bg-neutral-100 not-data-disabled:[&::part(trigger)]:active:bg-neutral-200 data-disabled:[&::part(trigger)]:border-neutral-500 data-disabled:[&::part(trigger)]:text-neutral-500 data-pressed:[&::part(trigger)]:bg-neutral-100 [&::part(trigger):focus-visible]:outline-2 [&::part(trigger):focus-visible]:-outline-offset-1 [&::part(trigger):focus-visible]:outline-neutral-950 dark:[&::part(trigger):focus-visible]:outline-white dark:[&::part(trigger)]:border-white dark:[&::part(trigger)]:bg-neutral-950 dark:[&::part(trigger)]:text-white dark:not-data-disabled:[&::part(trigger)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(trigger)]:active:bg-neutral-700 dark:data-disabled:[&::part(trigger)]:border-neutral-400 dark:data-disabled:[&::part(trigger)]:text-neutral-400 dark:data-pressed:[&::part(trigger)]:bg-neutral-800 [&::part(trigger)]:w-48">
            <fs-select-value class="data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400"></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner class="outline-none select-none z-10" side-offset="4">
            <fs-select-popup class="group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-select-scroll-up-arrow class="top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950"></fs-select-scroll-up-arrow>
              <fs-select-list class="relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6">${SERVER_TYPES.map(
                item => `
<fs-select-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950">
  <fs-select-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text class="col-start-2">${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow class="bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950"></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="numOfInstances">
      <fs-number-field-root class="flex flex-col items-start gap-1" min="1" max="64" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Number of instances</fs-field-label>
        <fs-number-field-group class="[&::part(group)]:flex [&::part(group)]:h-8">
          <fs-number-field-decrement class="[&::part(decrement)]:box-border [&::part(decrement)]:m-0 [&::part(decrement)]:p-0 [&::part(decrement)]:border-solid [&::part(decrement)]:[font-family:inherit] [&::part(decrement)]:[font-size:inherit] [&::part(decrement)]:[font-weight:inherit] [&::part(decrement)]:[line-height:inherit] [&::part(decrement)]:flex [&::part(decrement)]:h-full [&::part(decrement)]:w-8 [&::part(decrement)]:items-center [&::part(decrement)]:justify-center [&::part(decrement)]:rounded-none [&::part(decrement)]:border [&::part(decrement)]:border-neutral-950 [&::part(decrement)]:bg-white [&::part(decrement)]:bg-clip-padding [&::part(decrement)]:text-neutral-950 [&::part(decrement)]:outline-0 [&::part(decrement)]:select-none not-data-disabled:[&::part(decrement)]:hover:bg-neutral-100 not-data-disabled:[&::part(decrement)]:active:bg-neutral-200 data-disabled:[&::part(decrement)]:border-neutral-500 data-disabled:[&::part(decrement)]:text-neutral-500 [&::part(decrement):focus-visible]:z-1 [&::part(decrement):focus-visible]:outline-2 [&::part(decrement):focus-visible]:-outline-offset-1 [&::part(decrement):focus-visible]:outline-neutral-950 dark:[&::part(decrement):focus-visible]:outline-white dark:[&::part(decrement)]:border-white dark:[&::part(decrement)]:bg-neutral-950 dark:[&::part(decrement)]:text-white dark:not-data-disabled:[&::part(decrement)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(decrement)]:active:bg-neutral-700 dark:data-disabled:[&::part(decrement)]:border-neutral-400 dark:data-disabled:[&::part(decrement)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input class="h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white"></fs-number-field-input>
          <fs-number-field-increment class="[&::part(increment)]:box-border [&::part(increment)]:m-0 [&::part(increment)]:p-0 [&::part(increment)]:border-solid [&::part(increment)]:[font-family:inherit] [&::part(increment)]:[font-size:inherit] [&::part(increment)]:[font-weight:inherit] [&::part(increment)]:[line-height:inherit] [&::part(increment)]:flex [&::part(increment)]:h-full [&::part(increment)]:w-8 [&::part(increment)]:items-center [&::part(increment)]:justify-center [&::part(increment)]:rounded-none [&::part(increment)]:border [&::part(increment)]:border-neutral-950 [&::part(increment)]:bg-white [&::part(increment)]:bg-clip-padding [&::part(increment)]:text-neutral-950 [&::part(increment)]:outline-0 [&::part(increment)]:select-none not-data-disabled:[&::part(increment)]:hover:bg-neutral-100 not-data-disabled:[&::part(increment)]:active:bg-neutral-200 data-disabled:[&::part(increment)]:border-neutral-500 data-disabled:[&::part(increment)]:text-neutral-500 [&::part(increment):focus-visible]:z-1 [&::part(increment):focus-visible]:outline-2 [&::part(increment):focus-visible]:-outline-offset-1 [&::part(increment):focus-visible]:outline-neutral-950 dark:[&::part(increment):focus-visible]:outline-white dark:[&::part(increment)]:border-white dark:[&::part(increment)]:bg-neutral-950 dark:[&::part(increment)]:text-white dark:not-data-disabled:[&::part(increment)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(increment)]:active:bg-neutral-700 dark:data-disabled:[&::part(increment)]:border-neutral-400 dark:data-disabled:[&::part(increment)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="scalingThreshold">
        <fs-slider-root class="grid grid-cols-2 w-full gap-y-2" thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label class="text-sm font-bold text-neutral-950 dark:text-white">Scaling threshold</fs-slider-label>
          <fs-slider-value class="text-sm font-normal text-neutral-950 dark:text-white col-start-2 text-end"></fs-slider-value>
          <fs-slider-control class="flex col-span-2 touch-none items-center py-3 select-none">
            <fs-slider-track class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
              <fs-slider-indicator class="bg-neutral-950 select-none dark:bg-white"></fs-slider-indicator>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="storageType">
        <fs-radio-group aria-label="Storage type" class="flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white gap-4" default-value="ssd">
          <div class="text-sm font-bold text-neutral-950 dark:text-white -mt-px">Storage type</div>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'ssd' : 'SSD'}
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="hdd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'hdd' : 'HDD'}
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="restartOnFailure">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white gap-2'>
        Restart on failure
        <fs-switch-root class="flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white" default-checked="">
          <fs-switch-thumb class="[&::part(thumb)]:size-3.5 [&::part(thumb)]:bg-neutral-950 [&::part(thumb)]:transition-[translate,background-color] [&::part(thumb)]:duration-150 [&::part(thumb)]:ease-[ease] data-checked:[&::part(thumb)]:translate-x-4 data-checked:[&::part(thumb)]:bg-white dark:[&::part(thumb)]:bg-white dark:data-checked:[&::part(thumb)]:bg-neutral-950"></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols" class="flex flex-col items-start gap-1 text-neutral-950 dark:text-white">
          <div class="text-sm font-bold text-neutral-950 dark:text-white mb-2">Allowed network protocols</div>
          <div class="flex gap-4">
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="http">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="https">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssh">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button type="submit" class="[&::part(control)]:p-0 [&::part(control)]:flex [&::part(control)]:h-8 [&::part(control)]:items-center [&::part(control)]:justify-center [&::part(control)]:gap-2 [&::part(control)]:rounded-none [&::part(control)]:border [&::part(control)]:border-neutral-950 [&::part(control)]:bg-white [&::part(control)]:px-3 [&::part(control)]:py-0 [&::part(control)]:[font-family:inherit] [&::part(control)]:text-sm [&::part(control)]:leading-none [&::part(control)]:whitespace-nowrap [&::part(control)]:font-normal [&::part(control)]:text-neutral-950 [&::part(control)]:select-none not-data-disabled:[&::part(control)]:hover:bg-neutral-100 not-data-disabled:[&::part(control)]:active:bg-neutral-200 data-disabled:[&::part(control)]:border-neutral-500 data-disabled:[&::part(control)]:text-neutral-500 disabled:[&::part(control)]:border-neutral-500 disabled:[&::part(control)]:text-neutral-500 [&::part(control):focus-visible]:outline-2 [&::part(control):focus-visible]:-outline-offset-1 [&::part(control):focus-visible]:outline-neutral-950 dark:[&::part(control):focus-visible]:outline-white dark:[&::part(control)]:border-white dark:[&::part(control)]:bg-neutral-950 dark:[&::part(control)]:text-white dark:not-data-disabled:[&::part(control)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(control)]:active:bg-neutral-700 dark:data-disabled:[&::part(control)]:border-neutral-400 dark:data-disabled:[&::part(control)]:text-neutral-400 dark:disabled:[&::part(control)]:border-neutral-400 dark:disabled:[&::part(control)]:text-neutral-400 [&::part(control)]:mt-3">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

function themedFormHTML({ nativeForm = false }: FormOptions = {}): string {
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="handbook-form" aria-label="Launch new cloud server">
    <fs-field-root name="serverName">
      <fs-field-label>Server name</fs-field-label>
      <fs-field-control default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description>Must be 3 or more characters long</fs-field-description>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="region">
      <fs-combobox-root required="">
        <div>
          <fs-field-label>Region</fs-field-label>
          <fs-combobox-input-group>
            <fs-combobox-input placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div>
              <fs-combobox-clear>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner side-offset="4">
            <fs-combobox-popup>
              <fs-combobox-empty><div>No matches</div></fs-combobox-empty>
              <fs-combobox-list>${REGIONS.map(
                region => `
<fs-combobox-item value="${region}">
  <fs-combobox-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span>${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label>Container image</fs-field-label>
        <fs-autocomplete-input placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description>Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner data-fs-variant="hide-empty" side-offset="4">
            <fs-autocomplete-popup>
              <fs-autocomplete-list>${IMAGES.map(
                image => `
<fs-autocomplete-item data-fs-variant="stacked">
  <span>${image.name}</span>
  <span class="handbook-form-image-url">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="serverType">
      <fs-select-root required="">
        <div class="handbook-form-select">
          <fs-select-label>Server type</fs-select-label>
          <fs-select-trigger>
            <fs-select-value></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner side-offset="4">
            <fs-select-popup>
              <fs-select-scroll-up-arrow></fs-select-scroll-up-arrow>
              <fs-select-list>${SERVER_TYPES.map(
                item => `
<fs-select-item>
  <fs-select-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text>${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="numOfInstances">
      <fs-number-field-root min="1" max="64" required="">
        <fs-field-label>Number of instances</fs-field-label>
        <fs-number-field-group data-fs-variant="segmented">
          <fs-number-field-decrement>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input></fs-number-field-input>
          <fs-number-field-increment>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="scalingThreshold">
        <fs-slider-root thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label>Scaling threshold</fs-slider-label>
          <fs-slider-value></fs-slider-value>
          <fs-slider-control>
            <fs-slider-track>
              <fs-slider-indicator></fs-slider-indicator>
              <fs-slider-thumb index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root name="storageType">
        <fs-radio-group data-fs-variant="horizontal" aria-label="Storage type" default-value="ssd">
          <div class="handbook-form-group-label">Storage type</div>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="ssd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              SSD
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="hdd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              HDD
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root name="restartOnFailure">
      <fs-field-label>
        Restart on failure
        <fs-switch-root default-checked="">
          <fs-switch-thumb></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols">
          <div class="handbook-form-group-label handbook-form-protocol-heading">Allowed network protocols</div>
          <div class="handbook-form-protocols">
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="http">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="https">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="ssh">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button class="handbook-form-submit" type="submit">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="handbook-form-toast-viewport"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

export function configureForm(scope: ParentNode, { externalValidation = false }: FormOptions = {}) {
  const combobox = scope.querySelector('fs-combobox-root') as HTMLElement & Components.FsComboboxRoot;
  combobox.items = REGIONS;
  const autocomplete = scope.querySelector('fs-autocomplete-root') as HTMLElement & Components.FsAutocompleteRoot;
  autocomplete.items = IMAGES;
  autocomplete.itemToStringValue = (item: (typeof IMAGES)[number]) => item.url;
  scope.querySelectorAll('fs-autocomplete-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsAutocompleteItem).value = IMAGES[index];
  });
  (scope.querySelector('fs-select-root') as HTMLElement & Components.FsSelectRoot).items = SERVER_TYPES;
  scope.querySelectorAll('fs-select-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsSelectItem).value = SERVER_TYPES[index].value;
  });
  Object.assign(scope.querySelector('fs-slider-root')!, {
    defaultValue: [0.2, 0.8],
    format: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0 },
  });
  (scope.querySelector('fs-checkbox-group') as HTMLElement & Components.FsCheckboxGroup).defaultValue = [];
  if (externalValidation) {
    scope.querySelectorAll('[required], [minlength], [pattern]').forEach(element => {
      for (const name of ['required', 'minlength', 'pattern']) element.removeAttribute(name);
    });
    scope.querySelectorAll('fs-field-root').forEach(element => Object.assign(element, { invalid: false, touched: false, dirty: false }));
    scope.querySelectorAll('fs-field-error').forEach(element => {
      (element as HTMLElement & Components.FsFieldError).match = false;
      element.append(element.ownerDocument.createElement('span'));
    });
  }
  scope.querySelector('form')?.setAttribute('novalidate', '');
}

export function createForm(container: HTMLElement, options: FormOptions = {}) {
  const template = container.ownerDocument.createElement('template');
  template.innerHTML = formHTML(options);
  const content = template.content;
  // Arrays, item objects and callbacks are properties, not JSON attributes.
  // Set them before connecting the elements, including the initially offline Portal parts.
  configureForm(content, options);
  const provider = content.querySelector('fs-toast-provider') as HTMLElement & Components.FsToastProvider;
  const form = content.querySelector('fs-form, form') as HTMLElement & Components.FsForm;
  const fields = Object.fromEntries(fieldNames.map(name => [name, content.querySelector(`fs-field-root[name="${name}"]`)!])) as Record<
    keyof FormValues,
    HTMLElement & Components.FsFieldRoot
  >;
  const controls = Object.fromEntries(
    fieldNames.map(name => [
      name,
      fields[name].querySelector(
        'fs-field-control, fs-combobox-root, fs-autocomplete-root, fs-select-root, fs-number-field-root, fs-slider-root, fs-radio-group, fs-switch-root, fs-checkbox-group',
      )!,
    ]),
  ) as Record<keyof FormValues, HTMLElement>;
  const errors = Object.fromEntries(fieldNames.map(name => [name, fields[name].querySelector('fs-field-error')])) as Record<
    keyof FormValues,
    (HTMLElement & Components.FsFieldError) | null
  >;
  const toastViewport = content.querySelector('fs-toast-viewport')!;
  container.append(content);
  return { provider, form, fields, controls, errors, toastViewport, destroy: () => provider.remove() };
}
export type FormElements = ReturnType<typeof createForm>;
```

```tsx
/* button.tsx */
import * as React from 'react';
import { Button as BaseButton } from '@base-ui/react/button';
import clsx from 'clsx';

export function Button({ className, ...props }: React.ComponentPropsWithoutRef<'button'>) {
  return (
    <BaseButton
      type="button"
      className={clsx(
        'flex h-8 items-center justify-center gap-2 rounded-none border border-neutral-950 bg-white px-3 py-0 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 disabled:border-neutral-500 disabled:text-neutral-500 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:disabled:border-neutral-400 dark:disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';

export function CheckboxGroup({ className, ...props }: BaseCheckboxGroup.Props) {
  return <BaseCheckboxGroup className={clsx('flex flex-col items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* form.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Form as BaseForm } from '@base-ui/react/form';

export function Form({ className, ...props }: BaseForm.Props) {
  return <BaseForm className={clsx('flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]', className)} {...props} />;
}
```

```tsx
/* radio-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';

export function RadioGroup<Value>({ className, ...props }: BaseRadioGroup.Props<Value>) {
  return <BaseRadioGroup className={clsx('flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* toast.tsx */
'use client';
import * as React from 'react';
import { Toast } from '@base-ui/react/toast';

function Toasts() {
  const { toasts } = Toast.useToastManager();
  return toasts.map(toast => (
    <Toast.Root
      key={toast.id}
      toast={toast}
      className="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]"
    >
      <Toast.Content className="h-full overflow-hidden p-3 transition-opacity duration-250">
        <Toast.Title className="text-sm font-bold" />
        <Toast.Description className="text-sm text-neutral-700 dark:text-neutral-300" />
        <div className="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore>
          <pre className="whitespace-pre-wrap">{JSON.stringify(toast.data, null, 2)}</pre>
        </div>
        <Toast.Close
          className="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700"
          aria-label="Close"
        >
          <XIcon />
        </Toast.Close>
      </Toast.Content>
    </Toast.Root>
  ));
}

export function ToastProvider(props: { children: React.ReactNode }) {
  return (
    <Toast.Provider limit={1}>
      {props.children}
      <Toast.Portal>
        <Toast.Viewport className="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]">
          <Toasts />
        </Toast.Viewport>
      </Toast.Portal>
    </Toast.Provider>
  );
}

export const useToastManager = Toast.useToastManager;

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m2.5 2.5 11 11m-11 0 11-11" />
    </svg>
  );
}
```

```tsx
/* autocomplete.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Autocomplete } from '@base-ui/react/autocomplete';

export function Root(props: Autocomplete.Root.Props<any>) {
  return <Autocomplete.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Autocomplete.Input.Props>(function Input(
  { className, ...props }: Autocomplete.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Autocomplete.Input
      ref={forwardedRef}
      className={clsx(
        'h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Portal(props: Autocomplete.Portal.Props) {
  return <Autocomplete.Portal {...props} />;
}

export function Positioner({ className, ...props }: Autocomplete.Positioner.Props) {
  return <Autocomplete.Positioner className={clsx('outline-none data-empty:hidden', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Autocomplete.Popup.Props) {
  return (
    <Autocomplete.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Autocomplete.List.Props) {
  return (
    <Autocomplete.List
      className={clsx('max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Autocomplete.Item.Props) {
  return (
    <Autocomplete.Item
      className={clsx(
        'flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Checkbox } from '@base-ui/react/checkbox';

export function Root({ className, ...props }: Checkbox.Root.Props) {
  return (
    <Checkbox.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Checkbox.Indicator.Props) {
  return <Checkbox.Indicator className={clsx('flex data-unchecked:hidden', className)} {...props} />;
}
```

```tsx
/* combobox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Combobox } from '@base-ui/react/combobox';

export function Root(props: Combobox.Root.Props<any, any>) {
  return <Combobox.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Combobox.Input.Props>(function Input(
  { className, ...props }: Combobox.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Combobox.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function InputGroup({ className, ...props }: Combobox.InputGroup.Props) {
  return (
    <Combobox.InputGroup
      className={clsx(
        'relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>input]:pr-[2.5rem] has-[.combobox-clear]:[&>input]:pr-[calc(0.5rem+2rem*2)]',
        className,
      )}
      {...props}
    />
  );
}

export function Clear({ className, ...props }: Combobox.Clear.Props) {
  return (
    <Combobox.Clear
      className={clsx('combobox-clear flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)}
      {...props}
    >
      <XIcon />
    </Combobox.Clear>
  );
}

export function Trigger({ className, ...props }: Combobox.Trigger.Props) {
  return <Combobox.Trigger className={clsx('flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Portal(props: Combobox.Portal.Props) {
  return <Combobox.Portal {...props} />;
}

export function Positioner({ className, ...props }: Combobox.Positioner.Props) {
  return <Combobox.Positioner className={clsx('outline-none', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Combobox.Popup.Props) {
  return (
    <Combobox.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function Empty({ className, children, ...props }: Combobox.Empty.Props) {
  return (
    <Combobox.Empty {...props}>
      {children ? <div className={clsx('py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400', className)}>{children}</div> : null}
    </Combobox.Empty>
  );
}

export function List({ className, ...props }: Combobox.List.Props) {
  return (
    <Combobox.List
      className={clsx('outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Combobox.Item.Props) {
  return (
    <Combobox.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Combobox.ItemIndicator.Props) {
  return <Combobox.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function CaretDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M12 6H4l4 4.5z" />
    </svg>
  );
}

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m4.5 4.5 7 7m-7 0 7-7" />
    </svg>
  );
}
```

```tsx
/* field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Field } from '@base-ui/react/field';

export function Root({ className, ...props }: Field.Root.Props) {
  return <Field.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Label({ className, ...props }: Field.Label.Props) {
  return (
    <Field.Label
      className={clsx(
        'text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white',
        className,
      )}
      {...props}
    />
  );
}

export function Description({ className, ...props }: Field.Description.Props) {
  return <Field.Description className={clsx('text-sm text-neutral-600 dark:text-neutral-400', className)} {...props} />;
}

export const Control = React.forwardRef<HTMLInputElement, Field.Control.Props>(function FieldControl(
  { className, ...props }: Field.Control.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Field.Control
      ref={forwardedRef}
      className={clsx(
        'h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Error({ className, ...props }: Field.Error.Props) {
  return <Field.Error className={clsx('text-sm text-red-700 dark:text-red-400', className)} {...props} />;
}

export function Item(props: Field.Item.Props) {
  return <Field.Item {...props} />;
}
```

```tsx
/* fieldset.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Fieldset } from '@base-ui/react/fieldset';

export function Root(props: Fieldset.Root.Props) {
  return <Fieldset.Root {...props} />;
}

export function Legend({ className, ...props }: Fieldset.Legend.Props) {
  return <Fieldset.Legend className={clsx('text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* number-field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { NumberField } from '@base-ui/react/number-field';

export function Root({ className, ...props }: NumberField.Root.Props) {
  return <NumberField.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Group({ className, ...props }: NumberField.Group.Props) {
  return <NumberField.Group className={clsx('flex h-8', className)} {...props} />;
}

export function Decrement({ className, ...props }: NumberField.Decrement.Props) {
  return (
    <NumberField.Decrement
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}

export const Input = React.forwardRef<HTMLInputElement, NumberField.Input.Props>(function Input(
  { className, ...props }: NumberField.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <NumberField.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white',
        className,
      )}
      {...props}
    />
  );
});

export function Increment({ className, ...props }: NumberField.Increment.Props) {
  return (
    <NumberField.Increment
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* radio.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Radio } from '@base-ui/react/radio';

export function Root({ className, ...props }: Radio.Root.Props) {
  return (
    <Radio.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Radio.Indicator.Props) {
  return <Radio.Indicator className={clsx('flex items-center justify-center data-unchecked:hidden before:size-2 before:rounded-full before:bg-current', className)} {...props} />;
}
```

```tsx
/* select.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Select } from '@base-ui/react/select';

export function Root(props: Select.Root.Props<any>) {
  return <Select.Root {...props} />;
}

export function Label({ className, ...props }: Select.Label.Props) {
  return <Select.Label className={clsx('cursor-default text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Trigger({ className, ...props }: Select.Trigger.Props) {
  return (
    <Select.Trigger
      className={clsx(
        'flex h-8 min-w-40 cursor-default items-center justify-between gap-3 border border-neutral-950 bg-white pl-2 pr-1 text-sm font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 data-pressed:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:data-pressed:bg-neutral-800',
        className,
      )}
      {...props}
    />
  );
}

export function Value({ className, ...props }: Select.Value.Props) {
  return <Select.Value className={clsx('data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400', className)} {...props} />;
}

export function Icon(props: Select.Icon.Props) {
  return <Select.Icon {...props} />;
}

export function Portal(props: Select.Portal.Props) {
  return <Select.Portal {...props} />;
}

export function Positioner({ className, ...props }: Select.Positioner.Props) {
  return <Select.Positioner className={clsx('outline-none select-none z-10', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Select.Popup.Props) {
  return (
    <Select.Popup
      className={clsx(
        'group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function ScrollUpArrow({ className, ...props }: Select.ScrollUpArrow.Props) {
  return (
    <Select.ScrollUpArrow
      className={clsx(
        "top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function ScrollDownArrow({ className, ...props }: Select.ScrollDownArrow.Props) {
  return (
    <Select.ScrollDownArrow
      className={clsx(
        "bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Select.List.Props) {
  return <Select.List className={clsx('relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6', className)} {...props} />;
}

export function Item({ className, ...props }: Select.Item.Props) {
  return (
    <Select.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Select.ItemIndicator.Props) {
  return <Select.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function ItemText({ className, ...props }: Select.ItemText.Props) {
  return <Select.ItemText className={clsx('col-start-2', className)} {...props} />;
}
```

```tsx
/* slider.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Slider } from '@base-ui/react/slider';

export function Root({ className, ...props }: Slider.Root.Props<any>) {
  return <Slider.Root className={clsx('grid grid-cols-2', className)} {...props} />;
}

export function Value({ className, ...props }: Slider.Value.Props) {
  return <Slider.Value className={clsx('text-sm font-normal text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Control({ className, ...props }: Slider.Control.Props) {
  return <Slider.Control className={clsx('flex col-span-2 touch-none items-center py-3 select-none', className)} {...props} />;
}

export function Track({ className, ...props }: Slider.Track.Props) {
  return <Slider.Track className={clsx('h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800', className)} {...props} />;
}

export function Indicator({ className, ...props }: Slider.Indicator.Props) {
  return <Slider.Indicator className={clsx('bg-neutral-950 select-none dark:bg-white', className)} {...props} />;
}

export function Thumb({ className, ...props }: Slider.Thumb.Props) {
  return (
    <Slider.Thumb
      className={clsx(
        'size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* switch.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Switch } from '@base-ui/react/switch';

export function Root({ className, ...props }: Switch.Root.Props) {
  return (
    <Switch.Root
      className={clsx(
        'flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function Thumb({ className, ...props }: Switch.Thumb.Props) {
  return (
    <Switch.Thumb
      className={clsx(
        'size-3.5 bg-neutral-950 transition-[translate,background-color] duration-150 ease-[ease] data-checked:translate-x-4 data-checked:bg-white dark:bg-white dark:data-checked:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* stencil-react-hook-form.tsx */
'use client';

// React is required by React Hook Form. The form itself uses the native fs-*
// declarations in stencil-form.ts, with no React component wrappers.
import * as React from 'react';
import { flushSync } from 'react-dom';
import { Controller, useForm, type ControllerFieldState, type ControllerRenderProps } from 'react-hook-form';
import { createForm, defaultValues, fieldNames, type FormElements, type FormValues } from './stencil-form';
import { connectField } from './stencil-form-events';
import { connectToasts } from './stencil-toast';

function FieldConnection({ elements, field, state }: { elements: FormElements; field: ControllerRenderProps<FormValues, keyof FormValues>; state: ControllerFieldState }) {
  const connection = React.useRef<ReturnType<typeof connectField>>(null);
  React.useLayoutEffect(() => {
    // CustomEvent listeners run outside React's discrete input-event batching.
    // Commit controlled values before the next key press or pointer update.
    connection.current = connectField(elements, field.name, value => flushSync(() => field.onChange(value)), field.onBlur, field.ref);
    return () => connection.current?.destroy();
  }, [elements, field.name, field.onChange, field.onBlur, field.ref]);
  React.useLayoutEffect(() => {
    connection.current?.update({ value: field.value, invalid: state.invalid, dirty: state.isDirty, touched: state.isTouched, error: state.error?.message });
  });
  return null;
}

export default function StencilReactHookForm({ themed = false }: { themed?: boolean }) {
  const host = React.useRef<HTMLDivElement>(null);
  const [elements, setElements] = React.useState<FormElements | null>(null);
  const { control, handleSubmit } = useForm<FormValues>({ defaultValues });
  React.useLayoutEffect(() => {
    const form = createForm(host.current!, { externalValidation: true, themed });
    const toasts = connectToasts(form.provider, form.toastViewport, themed);
    const submit = (event: Event) => {
      event.preventDefault();
      void handleSubmit(values => {
        toasts.submit(values);
      })();
    };
    form.form.addEventListener('submit', submit);
    setElements(form);
    return () => {
      form.form.removeEventListener('submit', submit);
      toasts.destroy();
      form.destroy();
    };
  }, [handleSubmit, themed]);
  return (
    <>
      <div ref={host} style={{ display: 'contents' }} />
      {elements &&
        fieldNames.map(name => (
          <Controller
            key={name}
            name={name}
            control={control}
            rules={{
              required: ['serverName', 'region', 'containerImage', 'serverType', 'numOfInstances'].includes(name) ? 'This field is required.' : false,
              ...(name === 'serverName' ? { minLength: { value: 3, message: 'At least 3 characters.' } } : {}),
            }}
            render={({ field, fieldState }) => <FieldConnection elements={elements} field={field} state={fieldState} />}
          />
        ))}
    </>
  );
}
```

```css
/* stencil-form.css */
/* Shared layout for the three theme-based Handbook forms. */
@layer fs-theme {
  .handbook-form {
    --fs-form-gap: var(--fs-space-5);
    --fs-form-max-width: 16rem;
    --fs-field-max-width: none;
    --fs-combobox-input-group-width: 16rem;
    --fs-number-field-input-width: 4rem;
    --fs-number-field-input-border: 1px solid var(--fs-color-foreground);
    --fs-slider-root-width: 100%;
    --fs-slider-control-width: 100%;
    --fs-slider-label-font-weight: var(--fs-font-weight-bold);
    --fs-slider-root-row-gap: var(--fs-space-2);
    --fs-select-width: 12rem;
    --fs-select-line-height: var(--fs-line-height-sm);
  }
  /* TanStack's adapter owns a native form instead of fs-form. */
  form.handbook-form {
    display: flex;
    flex-direction: column;
    gap: var(--fs-form-gap);
    width: 100%;
    max-width: var(--fs-form-max-width);
  }
  .handbook-form-select {
    display: flex;
    flex-direction: column;
    gap: var(--fs-space-1);
    width: fit-content;
  }
  .handbook-form-group-label {
    font-size: var(--fs-font-size-sm);
    line-height: var(--fs-line-height-sm);
    font-weight: var(--fs-font-weight-bold);
    color: var(--fs-color-foreground);
  }
  :where([data-fs-variant='horizontal']) .handbook-form-group-label {
    margin-top: -1px;
  }
  .handbook-form-protocol-heading {
    margin-bottom: var(--fs-space-2);
  }
  .handbook-form-protocols {
    display: flex;
    gap: var(--fs-space-4);
  }
  .handbook-form-protocol-label {
    text-transform: uppercase;
  }
  .handbook-form-submit::part(control) {
    margin-top: var(--fs-space-3);
  }
  .handbook-form-image-url {
    font-family: 'Paper Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
    white-space: nowrap;
    font-size: 0.75rem;
    opacity: 0.8;
  }
  .handbook-form-toast-viewport {
    --fs-toast-viewport-z-index: 10;
    --fs-toast-viewport-width: 250px;
    --fs-toast-viewport-bottom: 1rem;
    --fs-toast-viewport-right: 1rem;
  }
  .handbook-form-submitted-values {
    margin-top: var(--fs-space-2);
    border: var(--fs-border-width) solid var(--fs-color-foreground);
    padding: var(--fs-space-2);
    font-size: 0.75rem;
    user-select: text;
  }
  .handbook-form-submitted-values pre {
    white-space: pre-wrap;
    font-size: 0.75rem;
    line-height: calc(1 / 0.75);
  }
  @media (min-width: 40rem) {
    .handbook-form {
      --fs-form-max-width: 20rem;
    }
    .handbook-form-toast-viewport {
      --fs-toast-viewport-width: 360px;
      --fs-toast-viewport-bottom: 2rem;
      --fs-toast-viewport-right: 2rem;
    }
  }
  @media (min-width: 48rem) {
    .handbook-form {
      --fs-autocomplete-input-width: 20rem;
    }
  }
}
```

```ts
/* stencil-form-events.ts */
import type { FormElements, FormValues } from './stencil-form';

export interface FieldState {
  value: FormValues[keyof FormValues];
  invalid: boolean;
  touched: boolean;
  dirty: boolean;
  error?: string;
}

/** The form library owns values and validation; the elements own their UI and ARIA. */
export function connectField(elements: FormElements, name: keyof FormValues, onChange: (value: any) => void, onBlur: () => void, inputRef?: (element: HTMLElement | null) => void) {
  const field = elements.fields[name];
  const control = elements.controls[name];
  const refTarget = name === 'scalingThreshold' ? field.querySelector('fs-slider-thumb')! : name === 'allowedNetworkProtocols' ? field.querySelector('fs-checkbox-root')! : control;
  const error = elements.errors[name];
  // Keep the authored text node: Field.Error can be offline while valid.
  const message = error?.querySelector('span');
  const valueProperty = name === 'restartOnFailure' ? 'checked' : 'value';
  const eventName = name === 'restartOnFailure' ? 'checkedChange' : 'valueChange';
  const change = (event: Event) => {
    if (event.target === control) onChange((event as CustomEvent).detail[valueProperty]);
  };
  control.addEventListener(eventName, change);
  if (name === 'scalingThreshold') control.addEventListener('valueCommitted', change);
  const blur = () => onBlur();
  field.addEventListener('focusout', blur);
  if (inputRef) {
    if (name === 'numOfInstances') inputRef(field.querySelector('fs-number-field-input'));
    else Reflect.set(refTarget, 'inputRef', inputRef);
  }
  return {
    update(state: FieldState) {
      Reflect.set(control, valueProperty, state.value);
      field.invalid = state.invalid;
      field.touched = state.touched;
      field.dirty = state.dirty;
      if (message) message.textContent = state.error ?? '';
      if (error) error.match = state.invalid;
    },
    destroy() {
      control.removeEventListener(eventName, change);
      control.removeEventListener('valueCommitted', change);
      field.removeEventListener('focusout', blur);
      if (inputRef) {
        Reflect.set(refTarget, 'inputRef', undefined);
        inputRef(null);
      }
    },
  };
}
```

```ts
/* stencil-toast.ts */
import { createToastManager, type ToastObject } from 'finesoft-components/toast';
import type { Components } from 'finesoft-components';

const toastHTML = `
<fs-toast-root class="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]">
  <fs-toast-content class="h-full overflow-hidden p-3 transition-opacity duration-250">
    <fs-toast-title class="text-sm font-bold"></fs-toast-title>
    <fs-toast-description class="text-sm text-neutral-700 dark:text-neutral-300"></fs-toast-description>
    <div class="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore="true">
      <pre class="whitespace-pre-wrap"></pre>
    </div>
    <fs-toast-close class="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700" aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

const themedToastHTML = `
<fs-toast-root data-fs-variant="rich">
  <fs-toast-content>
    <fs-toast-title></fs-toast-title>
    <fs-toast-description></fs-toast-description>
    <div class="handbook-form-submitted-values" data-base-ui-swipe-ignore="true">
      <pre></pre>
    </div>
    <fs-toast-close aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

export function connectToasts(provider: HTMLElement & Components.FsToastProvider, viewport: Element, themed = false) {
  const manager = createToastManager();
  const roots = new Map<string, HTMLElement & Components.FsToastRoot>();
  function update(event: CustomEvent<ToastObject[]>) {
    const toasts = event.detail;
    for (const [id, root] of roots) {
      if (!toasts.some(toast => toast.id === id)) {
        root.remove();
        roots.delete(id);
      }
    }
    for (const toast of toasts) {
      let root = roots.get(toast.id);
      if (!root) {
        const template = provider.ownerDocument.createElement('template');
        template.innerHTML = themed ? themedToastHTML : toastHTML;
        root = template.content.firstElementChild as HTMLElement & Components.FsToastRoot;
        root.toast = toast;
        root.querySelector('pre')!.textContent = JSON.stringify(toast.data, null, 2);
        roots.set(toast.id, root);
        viewport.append(root);
      } else {
        root.toast = toast;
      }
    }
  }
  provider.addEventListener('toastsChange', update as EventListener);
  provider.toastManager = manager;
  return {
    submit: (data: unknown) => manager.add({ title: 'Form submitted', description: 'The form contains these values:', data: data as Record<string, unknown> }),
    destroy: () => provider.removeEventListener('toastsChange', update as EventListener),
  };
}
```

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactExample from './react-react-hook-form';
import StencilExample from './stencil-react-hook-form';
import { formHTML, configureForm } from './stencil-form';

export default function Comparison() {
  const options = { externalValidation: true };
  return (
    <StencilComparison
      component="handbook-form-react-hook-form"
      react={<ReactExample />}
      stencil={null}
      renderSource={() => formHTML(options)}
      beforeHydrate={document => configureForm(document, options)}
      clientStencil={<StencilExample />}
    />
  );
}
```

```tsx
/* react-react-hook-form.tsx */
'use client';
import * as React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { Button } from './button';
import { CheckboxGroup } from './checkbox-group';
import { Form } from './form';
import { RadioGroup } from './radio-group';
import { ToastProvider, useToastManager } from './toast';
import * as Autocomplete from './autocomplete';
import * as Checkbox from './checkbox';
import * as Combobox from './combobox';
import * as Field from './field';
import * as Fieldset from './fieldset';
import * as NumberField from './number-field';
import * as Radio from './radio';
import * as Select from './select';
import * as Slider from './slider';
import * as Switch from './switch';

interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

function ReactHookForm() {
  const toastManager = useToastManager();

  const { control, handleSubmit } = useForm<FormValues>({
    defaultValues: {
      serverName: '',
      region: null,
      containerImage: '',
      serverType: null,
      numOfInstances: null,
      scalingThreshold: [0.2, 0.8],
      storageType: 'ssd',
      restartOnFailure: true,
      allowedNetworkProtocols: [],
    },
  });

  function submitForm(data: FormValues) {
    toastManager.add({
      title: 'Form submitted',
      description: 'The form contains these values:',
      data,
    });
  }

  return (
    <Form aria-label="Launch new cloud server" onSubmit={handleSubmit(submitForm)}>
      <Controller
        name="serverName"
        control={control}
        rules={{
          required: 'This field is required.',
          minLength: { value: 3, message: 'At least 3 characters.' },
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Field.Label>Server name</Field.Label>
            <Field.Control ref={ref} value={value} onBlur={onBlur} onValueChange={onChange} placeholder="e.g. api-server-01" />
            <Field.Description>Must be 3 or more characters long</Field.Description>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="region"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Combobox.Root items={REGIONS} value={value} onValueChange={onChange}>
              <div className="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
                <Field.Label className="mb-1 block">Region</Field.Label>
                <Combobox.InputGroup>
                  <Combobox.Input placeholder="e.g. eu-central-1" ref={ref} onBlur={onBlur} />
                  <div className="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
                    <Combobox.Clear />
                    <Combobox.Trigger>
                      <Combobox.CaretDownIcon />
                    </Combobox.Trigger>
                  </div>
                </Combobox.InputGroup>
              </div>
              <Combobox.Portal>
                <Combobox.Positioner>
                  <Combobox.Popup>
                    <Combobox.Empty>No matches</Combobox.Empty>
                    <Combobox.List>
                      {(region: string) => {
                        return (
                          <Combobox.Item key={region} value={region}>
                            <Combobox.ItemIndicator>
                              <CheckIcon />
                            </Combobox.ItemIndicator>
                            <span className="col-start-2">{region}</span>
                          </Combobox.Item>
                        );
                      }}
                    </Combobox.List>
                  </Combobox.Popup>
                </Combobox.Positioner>
              </Combobox.Portal>
            </Combobox.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="containerImage"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Autocomplete.Root items={IMAGES} mode="both" itemToStringValue={(itemValue: Image) => itemValue.url} value={value} onValueChange={onChange}>
              <Field.Label>Container image</Field.Label>
              <Autocomplete.Input placeholder="e.g. docker.io/library/node:latest" ref={ref} onBlur={onBlur} />
              <Field.Description>Enter a registry URL with optional tags</Field.Description>
              <Autocomplete.Portal>
                <Autocomplete.Positioner>
                  <Autocomplete.Popup>
                    <Autocomplete.List>
                      {(image: Image) => {
                        return (
                          <Autocomplete.Item key={image.url} value={image}>
                            <span>{image.name}</span>
                            <span className="font-mono whitespace-nowrap text-xs opacity-80">{image.url}</span>
                          </Autocomplete.Item>
                        );
                      }}
                    </Autocomplete.List>
                  </Autocomplete.Popup>
                </Autocomplete.Positioner>
              </Autocomplete.Portal>
            </Autocomplete.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="serverType"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Select.Root items={SERVER_TYPES} value={value} onValueChange={onChange} inputRef={ref}>
              <div className="w-fit space-y-1">
                <Select.Label>Server type</Select.Label>
                <Select.Trigger className="w-48" onBlur={onBlur}>
                  <Select.Value />
                  <Select.Icon>
                    <CaretUpDownIcon />
                  </Select.Icon>
                </Select.Trigger>
              </div>
              <Select.Portal>
                <Select.Positioner>
                  <Select.Popup>
                    <Select.ScrollUpArrow />
                    <Select.List>
                      {SERVER_TYPES.map(({ label, value: serverType }) => {
                        return (
                          <Select.Item key={serverType} value={serverType}>
                            <Select.ItemIndicator>
                              <CheckIcon />
                            </Select.ItemIndicator>
                            <Select.ItemText>{label}</Select.ItemText>
                          </Select.Item>
                        );
                      })}
                    </Select.List>
                    <Select.ScrollDownArrow />
                  </Select.Popup>
                </Select.Positioner>
              </Select.Portal>
            </Select.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="numOfInstances"
        control={control}
        rules={{
          required: 'This field is required.',
        }}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty, error } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <NumberField.Root value={value} min={1} max={64} onValueChange={onChange}>
              <Field.Label>Number of instances</Field.Label>
              <NumberField.Group>
                <NumberField.Decrement>
                  <MinusIcon />
                </NumberField.Decrement>
                <NumberField.Input ref={ref} onBlur={onBlur} />
                <NumberField.Increment>
                  <PlusIcon />
                </NumberField.Increment>
              </NumberField.Group>
            </NumberField.Root>
            <Field.Error match={!!error}>{error?.message}</Field.Error>
          </Field.Root>
        )}
      />

      <Controller
        name="scalingThreshold"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Fieldset.Root
              render={
                <Slider.Root
                  value={value}
                  onValueChange={onChange}
                  onValueCommitted={onChange}
                  thumbAlignment="edge"
                  min={0}
                  max={1}
                  step={0.01}
                  format={{
                    style: 'percent',
                    minimumFractionDigits: 0,
                    maximumFractionDigits: 0,
                  }}
                  className="w-full gap-y-2"
                />
              }
            >
              <Fieldset.Legend>Scaling threshold</Fieldset.Legend>
              <Slider.Value className="col-start-2 text-end" />
              <Slider.Control>
                <Slider.Track>
                  <Slider.Indicator />
                  <Slider.Thumb index={0} aria-label="Minimum threshold" onBlur={onBlur} inputRef={ref} />
                  <Slider.Thumb index={1} aria-label="Maximum threshold" onBlur={onBlur} />
                </Slider.Track>
              </Slider.Control>
            </Fieldset.Root>
          </Field.Root>
        )}
      />

      <Controller
        name="storageType"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Fieldset.Root render={<RadioGroup className="gap-4" value={value} onValueChange={onChange} inputRef={ref} />}>
              <Fieldset.Legend className="-mt-px">Storage type</Fieldset.Legend>
              <Field.Item>
                <Field.Label>
                  <Radio.Root value="ssd" onBlur={onBlur}>
                    <Radio.Indicator />
                  </Radio.Root>
                  SSD
                </Field.Label>
              </Field.Item>
              <Field.Item>
                <Field.Label>
                  <Radio.Root value="hdd" onBlur={onBlur}>
                    <Radio.Indicator />
                  </Radio.Root>
                  HDD
                </Field.Label>
              </Field.Item>
            </Fieldset.Root>
          </Field.Root>
        )}
      />

      <Controller
        name="restartOnFailure"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Field.Label className="gap-2">
              Restart on failure
              <Switch.Root checked={value} inputRef={ref} onCheckedChange={onChange} onBlur={onBlur}>
                <Switch.Thumb />
              </Switch.Root>
            </Field.Label>
          </Field.Root>
        )}
      />

      <Controller
        name="allowedNetworkProtocols"
        control={control}
        render={({ field: { ref, name, value, onBlur, onChange }, fieldState: { invalid, isTouched, isDirty } }) => (
          <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
            <Fieldset.Root render={<CheckboxGroup value={value} onValueChange={onChange} />}>
              <Fieldset.Legend className="mb-2">Allowed network protocols</Fieldset.Legend>
              <div className="flex gap-4">
                {['http', 'https', 'ssh'].map(val => {
                  return (
                    <Field.Item key={val}>
                      <Field.Label className="uppercase">
                        <Checkbox.Root value={val} inputRef={val === 'http' ? ref : undefined} onBlur={onBlur}>
                          <Checkbox.Indicator>
                            <CheckIcon />
                          </Checkbox.Indicator>
                        </Checkbox.Root>
                        {val}
                      </Field.Label>
                    </Field.Item>
                  );
                })}
              </div>
            </Fieldset.Root>
          </Field.Root>
        )}
      />

      <Button type="submit" className="mt-3">
        Launch server
      </Button>
    </Form>
  );
}

export default function App() {
  return (
    <ToastProvider>
      <ReactHookForm />
    </ToastProvider>
  );
}

function CaretUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="m2.5 8.5 4 4 7-9" />
    </svg>
  );
}

function PlusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13M8 14.5v-13" />
    </svg>
  );
}

function MinusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13" />
    </svg>
  );
}

function cartesian<T extends string[][]>(...arrays: T): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}

const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));

interface Image {
  url: string;
  name: string;
}
/* prettier-ignore */
const IMAGES: Image[] = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map((name) => ({
  url: `docker.io/library/${name}`,
  name,
}));

const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];
```

```tsx
/* stencil-react-hook-form.tsx */
'use client';

// React is required by React Hook Form. The form itself uses the native fs-*
// declarations in stencil-form.ts, with no React component wrappers.
import * as React from 'react';
import { flushSync } from 'react-dom';
import { Controller, useForm, type ControllerFieldState, type ControllerRenderProps } from 'react-hook-form';
import { createForm, defaultValues, fieldNames, type FormElements, type FormValues } from './stencil-form';
import { connectField } from './stencil-form-events';
import { connectToasts } from './stencil-toast';

function FieldConnection({ elements, field, state }: { elements: FormElements; field: ControllerRenderProps<FormValues, keyof FormValues>; state: ControllerFieldState }) {
  const connection = React.useRef<ReturnType<typeof connectField>>(null);
  React.useLayoutEffect(() => {
    // CustomEvent listeners run outside React's discrete input-event batching.
    // Commit controlled values before the next key press or pointer update.
    connection.current = connectField(elements, field.name, value => flushSync(() => field.onChange(value)), field.onBlur, field.ref);
    return () => connection.current?.destroy();
  }, [elements, field.name, field.onChange, field.onBlur, field.ref]);
  React.useLayoutEffect(() => {
    connection.current?.update({ value: field.value, invalid: state.invalid, dirty: state.isDirty, touched: state.isTouched, error: state.error?.message });
  });
  return null;
}

export default function StencilReactHookForm({ themed = false }: { themed?: boolean }) {
  const host = React.useRef<HTMLDivElement>(null);
  const [elements, setElements] = React.useState<FormElements | null>(null);
  const { control, handleSubmit } = useForm<FormValues>({ defaultValues });
  React.useLayoutEffect(() => {
    const form = createForm(host.current!, { externalValidation: true, themed });
    const toasts = connectToasts(form.provider, form.toastViewport, themed);
    const submit = (event: Event) => {
      event.preventDefault();
      void handleSubmit(values => {
        toasts.submit(values);
      })();
    };
    form.form.addEventListener('submit', submit);
    setElements(form);
    return () => {
      form.form.removeEventListener('submit', submit);
      toasts.destroy();
      form.destroy();
    };
  }, [handleSubmit, themed]);
  return (
    <>
      <div ref={host} style={{ display: 'contents' }} />
      {elements &&
        fieldNames.map(name => (
          <Controller
            key={name}
            name={name}
            control={control}
            rules={{
              required: ['serverName', 'region', 'containerImage', 'serverType', 'numOfInstances'].includes(name) ? 'This field is required.' : false,
              ...(name === 'serverName' ? { minLength: { value: 3, message: 'At least 3 characters.' } } : {}),
            }}
            render={({ field, fieldState }) => <FieldConnection elements={elements} field={field} state={fieldState} />}
          />
        ))}
    </>
  );
}
```

```ts
/* stencil-form.ts */
import type { Components } from 'finesoft-components';

export interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

export const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};
export const fieldNames = Object.keys(defaultValues) as Array<keyof FormValues>;
export interface FormOptions {
  externalValidation?: boolean;
  nativeForm?: boolean;
  themed?: boolean;
}

function cartesian(...arrays: string[][]): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}
const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));
const IMAGES = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map(name => ({ name, url: `docker.io/library/${name}` }));
const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];

// This same Web Components declaration is used by the browser and by Stencil SSR.
// The framework integrations below only exchange public properties and events.
export function formHTML(options: FormOptions = {}): string {
  if (options.themed) return themedFormHTML(options);
  const { nativeForm = false } = options;
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]" aria-label="Launch new cloud server">
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverName">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Server name</fs-field-label>
      <fs-field-control class="h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Must be 3 or more characters long</fs-field-description>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="region">
      <fs-combobox-root required="">
        <div class="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
          <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white mb-1 block'>Region</fs-field-label>
          <fs-combobox-input-group class="relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>fs-combobox-input>input]:pr-[2.5rem] has-[.combobox-clear]:[&>fs-combobox-input>input]:pr-[calc(0.5rem+2rem*2)]">
            <fs-combobox-input class="h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div class="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
              <fs-combobox-clear class="[&::part(clear)]:box-border [&::part(clear)]:m-0 [&::part(clear)]:p-0 [&::part(clear)]:border-solid [&::part(clear)]:[font-family:inherit] [&::part(clear)]:[font-size:inherit] [&::part(clear)]:[font-weight:inherit] [&::part(clear)]:[line-height:inherit] combobox-clear [&::part(clear)]:flex [&::part(clear)]:h-full [&::part(clear)]:w-6 [&::part(clear)]:items-center [&::part(clear)]:justify-center [&::part(clear)]:border-0 [&::part(clear)]:bg-transparent [&::part(clear)]:p-0 [&::part(clear)]:text-neutral-950 dark:[&::part(clear)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:p-0 [&::part(trigger)]:border-solid [&::part(trigger)]:[font-family:inherit] [&::part(trigger)]:[font-size:inherit] [&::part(trigger)]:[font-weight:inherit] [&::part(trigger)]:[line-height:inherit] [&::part(trigger)]:flex [&::part(trigger)]:h-full [&::part(trigger)]:w-6 [&::part(trigger)]:items-center [&::part(trigger)]:justify-center [&::part(trigger)]:border-0 [&::part(trigger)]:bg-transparent [&::part(trigger)]:p-0 [&::part(trigger)]:text-neutral-950 dark:[&::part(trigger)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner class="outline-none" side-offset="4">
            <fs-combobox-popup class="w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-combobox-empty>
                <div class="py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400">No matches</div>
              </fs-combobox-empty>
              <fs-combobox-list class="outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0">${REGIONS.map(
                region => `
<fs-combobox-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white" value="${region}">
  <fs-combobox-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span class="col-start-2">${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Container image</fs-field-label>
        <fs-autocomplete-input class="h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner class="outline-none data-empty:hidden" side-offset="4">
            <fs-autocomplete-popup class="w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-autocomplete-list class="max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0">${IMAGES.map(
                image => `
<fs-autocomplete-item class="flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white">
  <span>${image.name}</span>
  <span class="font-mono whitespace-nowrap text-xs opacity-80">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverType">
      <fs-select-root required="">
        <div class="w-fit space-y-1">
          <fs-select-label class="cursor-default text-sm font-bold text-neutral-950 dark:text-white">Server type</fs-select-label>
          <fs-select-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:font-[inherit] [&::part(trigger)]:border-solid [&::part(trigger)]:p-0 [&::part(trigger)]:flex [&::part(trigger)]:h-8 [&::part(trigger)]:min-w-40 [&::part(trigger)]:cursor-default [&::part(trigger)]:items-center [&::part(trigger)]:justify-between [&::part(trigger)]:gap-3 [&::part(trigger)]:border [&::part(trigger)]:border-neutral-950 [&::part(trigger)]:bg-white [&::part(trigger)]:pl-2 [&::part(trigger)]:pr-1 [&::part(trigger)]:text-sm [&::part(trigger)]:font-normal [&::part(trigger)]:text-neutral-950 [&::part(trigger)]:select-none not-data-disabled:[&::part(trigger)]:hover:bg-neutral-100 not-data-disabled:[&::part(trigger)]:active:bg-neutral-200 data-disabled:[&::part(trigger)]:border-neutral-500 data-disabled:[&::part(trigger)]:text-neutral-500 data-pressed:[&::part(trigger)]:bg-neutral-100 [&::part(trigger):focus-visible]:outline-2 [&::part(trigger):focus-visible]:-outline-offset-1 [&::part(trigger):focus-visible]:outline-neutral-950 dark:[&::part(trigger):focus-visible]:outline-white dark:[&::part(trigger)]:border-white dark:[&::part(trigger)]:bg-neutral-950 dark:[&::part(trigger)]:text-white dark:not-data-disabled:[&::part(trigger)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(trigger)]:active:bg-neutral-700 dark:data-disabled:[&::part(trigger)]:border-neutral-400 dark:data-disabled:[&::part(trigger)]:text-neutral-400 dark:data-pressed:[&::part(trigger)]:bg-neutral-800 [&::part(trigger)]:w-48">
            <fs-select-value class="data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400"></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner class="outline-none select-none z-10" side-offset="4">
            <fs-select-popup class="group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-select-scroll-up-arrow class="top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950"></fs-select-scroll-up-arrow>
              <fs-select-list class="relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6">${SERVER_TYPES.map(
                item => `
<fs-select-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950">
  <fs-select-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text class="col-start-2">${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow class="bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950"></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="numOfInstances">
      <fs-number-field-root class="flex flex-col items-start gap-1" min="1" max="64" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Number of instances</fs-field-label>
        <fs-number-field-group class="[&::part(group)]:flex [&::part(group)]:h-8">
          <fs-number-field-decrement class="[&::part(decrement)]:box-border [&::part(decrement)]:m-0 [&::part(decrement)]:p-0 [&::part(decrement)]:border-solid [&::part(decrement)]:[font-family:inherit] [&::part(decrement)]:[font-size:inherit] [&::part(decrement)]:[font-weight:inherit] [&::part(decrement)]:[line-height:inherit] [&::part(decrement)]:flex [&::part(decrement)]:h-full [&::part(decrement)]:w-8 [&::part(decrement)]:items-center [&::part(decrement)]:justify-center [&::part(decrement)]:rounded-none [&::part(decrement)]:border [&::part(decrement)]:border-neutral-950 [&::part(decrement)]:bg-white [&::part(decrement)]:bg-clip-padding [&::part(decrement)]:text-neutral-950 [&::part(decrement)]:outline-0 [&::part(decrement)]:select-none not-data-disabled:[&::part(decrement)]:hover:bg-neutral-100 not-data-disabled:[&::part(decrement)]:active:bg-neutral-200 data-disabled:[&::part(decrement)]:border-neutral-500 data-disabled:[&::part(decrement)]:text-neutral-500 [&::part(decrement):focus-visible]:z-1 [&::part(decrement):focus-visible]:outline-2 [&::part(decrement):focus-visible]:-outline-offset-1 [&::part(decrement):focus-visible]:outline-neutral-950 dark:[&::part(decrement):focus-visible]:outline-white dark:[&::part(decrement)]:border-white dark:[&::part(decrement)]:bg-neutral-950 dark:[&::part(decrement)]:text-white dark:not-data-disabled:[&::part(decrement)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(decrement)]:active:bg-neutral-700 dark:data-disabled:[&::part(decrement)]:border-neutral-400 dark:data-disabled:[&::part(decrement)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input class="h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white"></fs-number-field-input>
          <fs-number-field-increment class="[&::part(increment)]:box-border [&::part(increment)]:m-0 [&::part(increment)]:p-0 [&::part(increment)]:border-solid [&::part(increment)]:[font-family:inherit] [&::part(increment)]:[font-size:inherit] [&::part(increment)]:[font-weight:inherit] [&::part(increment)]:[line-height:inherit] [&::part(increment)]:flex [&::part(increment)]:h-full [&::part(increment)]:w-8 [&::part(increment)]:items-center [&::part(increment)]:justify-center [&::part(increment)]:rounded-none [&::part(increment)]:border [&::part(increment)]:border-neutral-950 [&::part(increment)]:bg-white [&::part(increment)]:bg-clip-padding [&::part(increment)]:text-neutral-950 [&::part(increment)]:outline-0 [&::part(increment)]:select-none not-data-disabled:[&::part(increment)]:hover:bg-neutral-100 not-data-disabled:[&::part(increment)]:active:bg-neutral-200 data-disabled:[&::part(increment)]:border-neutral-500 data-disabled:[&::part(increment)]:text-neutral-500 [&::part(increment):focus-visible]:z-1 [&::part(increment):focus-visible]:outline-2 [&::part(increment):focus-visible]:-outline-offset-1 [&::part(increment):focus-visible]:outline-neutral-950 dark:[&::part(increment):focus-visible]:outline-white dark:[&::part(increment)]:border-white dark:[&::part(increment)]:bg-neutral-950 dark:[&::part(increment)]:text-white dark:not-data-disabled:[&::part(increment)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(increment)]:active:bg-neutral-700 dark:data-disabled:[&::part(increment)]:border-neutral-400 dark:data-disabled:[&::part(increment)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="scalingThreshold">
        <fs-slider-root class="grid grid-cols-2 w-full gap-y-2" thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label class="text-sm font-bold text-neutral-950 dark:text-white">Scaling threshold</fs-slider-label>
          <fs-slider-value class="text-sm font-normal text-neutral-950 dark:text-white col-start-2 text-end"></fs-slider-value>
          <fs-slider-control class="flex col-span-2 touch-none items-center py-3 select-none">
            <fs-slider-track class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
              <fs-slider-indicator class="bg-neutral-950 select-none dark:bg-white"></fs-slider-indicator>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="storageType">
        <fs-radio-group aria-label="Storage type" class="flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white gap-4" default-value="ssd">
          <div class="text-sm font-bold text-neutral-950 dark:text-white -mt-px">Storage type</div>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'ssd' : 'SSD'}
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="hdd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'hdd' : 'HDD'}
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="restartOnFailure">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white gap-2'>
        Restart on failure
        <fs-switch-root class="flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white" default-checked="">
          <fs-switch-thumb class="[&::part(thumb)]:size-3.5 [&::part(thumb)]:bg-neutral-950 [&::part(thumb)]:transition-[translate,background-color] [&::part(thumb)]:duration-150 [&::part(thumb)]:ease-[ease] data-checked:[&::part(thumb)]:translate-x-4 data-checked:[&::part(thumb)]:bg-white dark:[&::part(thumb)]:bg-white dark:data-checked:[&::part(thumb)]:bg-neutral-950"></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols" class="flex flex-col items-start gap-1 text-neutral-950 dark:text-white">
          <div class="text-sm font-bold text-neutral-950 dark:text-white mb-2">Allowed network protocols</div>
          <div class="flex gap-4">
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="http">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="https">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssh">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button type="submit" class="[&::part(control)]:p-0 [&::part(control)]:flex [&::part(control)]:h-8 [&::part(control)]:items-center [&::part(control)]:justify-center [&::part(control)]:gap-2 [&::part(control)]:rounded-none [&::part(control)]:border [&::part(control)]:border-neutral-950 [&::part(control)]:bg-white [&::part(control)]:px-3 [&::part(control)]:py-0 [&::part(control)]:[font-family:inherit] [&::part(control)]:text-sm [&::part(control)]:leading-none [&::part(control)]:whitespace-nowrap [&::part(control)]:font-normal [&::part(control)]:text-neutral-950 [&::part(control)]:select-none not-data-disabled:[&::part(control)]:hover:bg-neutral-100 not-data-disabled:[&::part(control)]:active:bg-neutral-200 data-disabled:[&::part(control)]:border-neutral-500 data-disabled:[&::part(control)]:text-neutral-500 disabled:[&::part(control)]:border-neutral-500 disabled:[&::part(control)]:text-neutral-500 [&::part(control):focus-visible]:outline-2 [&::part(control):focus-visible]:-outline-offset-1 [&::part(control):focus-visible]:outline-neutral-950 dark:[&::part(control):focus-visible]:outline-white dark:[&::part(control)]:border-white dark:[&::part(control)]:bg-neutral-950 dark:[&::part(control)]:text-white dark:not-data-disabled:[&::part(control)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(control)]:active:bg-neutral-700 dark:data-disabled:[&::part(control)]:border-neutral-400 dark:data-disabled:[&::part(control)]:text-neutral-400 dark:disabled:[&::part(control)]:border-neutral-400 dark:disabled:[&::part(control)]:text-neutral-400 [&::part(control)]:mt-3">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

function themedFormHTML({ nativeForm = false }: FormOptions = {}): string {
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="handbook-form" aria-label="Launch new cloud server">
    <fs-field-root name="serverName">
      <fs-field-label>Server name</fs-field-label>
      <fs-field-control default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description>Must be 3 or more characters long</fs-field-description>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="region">
      <fs-combobox-root required="">
        <div>
          <fs-field-label>Region</fs-field-label>
          <fs-combobox-input-group>
            <fs-combobox-input placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div>
              <fs-combobox-clear>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner side-offset="4">
            <fs-combobox-popup>
              <fs-combobox-empty><div>No matches</div></fs-combobox-empty>
              <fs-combobox-list>${REGIONS.map(
                region => `
<fs-combobox-item value="${region}">
  <fs-combobox-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span>${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label>Container image</fs-field-label>
        <fs-autocomplete-input placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description>Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner data-fs-variant="hide-empty" side-offset="4">
            <fs-autocomplete-popup>
              <fs-autocomplete-list>${IMAGES.map(
                image => `
<fs-autocomplete-item data-fs-variant="stacked">
  <span>${image.name}</span>
  <span class="handbook-form-image-url">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="serverType">
      <fs-select-root required="">
        <div class="handbook-form-select">
          <fs-select-label>Server type</fs-select-label>
          <fs-select-trigger>
            <fs-select-value></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner side-offset="4">
            <fs-select-popup>
              <fs-select-scroll-up-arrow></fs-select-scroll-up-arrow>
              <fs-select-list>${SERVER_TYPES.map(
                item => `
<fs-select-item>
  <fs-select-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text>${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="numOfInstances">
      <fs-number-field-root min="1" max="64" required="">
        <fs-field-label>Number of instances</fs-field-label>
        <fs-number-field-group data-fs-variant="segmented">
          <fs-number-field-decrement>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input></fs-number-field-input>
          <fs-number-field-increment>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="scalingThreshold">
        <fs-slider-root thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label>Scaling threshold</fs-slider-label>
          <fs-slider-value></fs-slider-value>
          <fs-slider-control>
            <fs-slider-track>
              <fs-slider-indicator></fs-slider-indicator>
              <fs-slider-thumb index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root name="storageType">
        <fs-radio-group data-fs-variant="horizontal" aria-label="Storage type" default-value="ssd">
          <div class="handbook-form-group-label">Storage type</div>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="ssd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              SSD
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="hdd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              HDD
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root name="restartOnFailure">
      <fs-field-label>
        Restart on failure
        <fs-switch-root default-checked="">
          <fs-switch-thumb></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols">
          <div class="handbook-form-group-label handbook-form-protocol-heading">Allowed network protocols</div>
          <div class="handbook-form-protocols">
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="http">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="https">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="ssh">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button class="handbook-form-submit" type="submit">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="handbook-form-toast-viewport"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

export function configureForm(scope: ParentNode, { externalValidation = false }: FormOptions = {}) {
  const combobox = scope.querySelector('fs-combobox-root') as HTMLElement & Components.FsComboboxRoot;
  combobox.items = REGIONS;
  const autocomplete = scope.querySelector('fs-autocomplete-root') as HTMLElement & Components.FsAutocompleteRoot;
  autocomplete.items = IMAGES;
  autocomplete.itemToStringValue = (item: (typeof IMAGES)[number]) => item.url;
  scope.querySelectorAll('fs-autocomplete-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsAutocompleteItem).value = IMAGES[index];
  });
  (scope.querySelector('fs-select-root') as HTMLElement & Components.FsSelectRoot).items = SERVER_TYPES;
  scope.querySelectorAll('fs-select-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsSelectItem).value = SERVER_TYPES[index].value;
  });
  Object.assign(scope.querySelector('fs-slider-root')!, {
    defaultValue: [0.2, 0.8],
    format: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0 },
  });
  (scope.querySelector('fs-checkbox-group') as HTMLElement & Components.FsCheckboxGroup).defaultValue = [];
  if (externalValidation) {
    scope.querySelectorAll('[required], [minlength], [pattern]').forEach(element => {
      for (const name of ['required', 'minlength', 'pattern']) element.removeAttribute(name);
    });
    scope.querySelectorAll('fs-field-root').forEach(element => Object.assign(element, { invalid: false, touched: false, dirty: false }));
    scope.querySelectorAll('fs-field-error').forEach(element => {
      (element as HTMLElement & Components.FsFieldError).match = false;
      element.append(element.ownerDocument.createElement('span'));
    });
  }
  scope.querySelector('form')?.setAttribute('novalidate', '');
}

export function createForm(container: HTMLElement, options: FormOptions = {}) {
  const template = container.ownerDocument.createElement('template');
  template.innerHTML = formHTML(options);
  const content = template.content;
  // Arrays, item objects and callbacks are properties, not JSON attributes.
  // Set them before connecting the elements, including the initially offline Portal parts.
  configureForm(content, options);
  const provider = content.querySelector('fs-toast-provider') as HTMLElement & Components.FsToastProvider;
  const form = content.querySelector('fs-form, form') as HTMLElement & Components.FsForm;
  const fields = Object.fromEntries(fieldNames.map(name => [name, content.querySelector(`fs-field-root[name="${name}"]`)!])) as Record<
    keyof FormValues,
    HTMLElement & Components.FsFieldRoot
  >;
  const controls = Object.fromEntries(
    fieldNames.map(name => [
      name,
      fields[name].querySelector(
        'fs-field-control, fs-combobox-root, fs-autocomplete-root, fs-select-root, fs-number-field-root, fs-slider-root, fs-radio-group, fs-switch-root, fs-checkbox-group',
      )!,
    ]),
  ) as Record<keyof FormValues, HTMLElement>;
  const errors = Object.fromEntries(fieldNames.map(name => [name, fields[name].querySelector('fs-field-error')])) as Record<
    keyof FormValues,
    (HTMLElement & Components.FsFieldError) | null
  >;
  const toastViewport = content.querySelector('fs-toast-viewport')!;
  container.append(content);
  return { provider, form, fields, controls, errors, toastViewport, destroy: () => provider.remove() };
}
export type FormElements = ReturnType<typeof createForm>;
```

```tsx
/* button.tsx */
import * as React from 'react';
import { Button as BaseButton } from '@base-ui/react/button';
import clsx from 'clsx';

export function Button({ className, ...props }: React.ComponentPropsWithoutRef<'button'>) {
  return (
    <BaseButton
      type="button"
      className={clsx(
        'flex h-8 items-center justify-center gap-2 rounded-none border border-neutral-950 bg-white px-3 py-0 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 disabled:border-neutral-500 disabled:text-neutral-500 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:disabled:border-neutral-400 dark:disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';

export function CheckboxGroup({ className, ...props }: BaseCheckboxGroup.Props) {
  return <BaseCheckboxGroup className={clsx('flex flex-col items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* form.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Form as BaseForm } from '@base-ui/react/form';

export function Form({ className, ...props }: BaseForm.Props) {
  return <BaseForm className={clsx('flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]', className)} {...props} />;
}
```

```tsx
/* radio-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';

export function RadioGroup<Value>({ className, ...props }: BaseRadioGroup.Props<Value>) {
  return <BaseRadioGroup className={clsx('flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* toast.tsx */
'use client';
import * as React from 'react';
import { Toast } from '@base-ui/react/toast';

function Toasts() {
  const { toasts } = Toast.useToastManager();
  return toasts.map(toast => (
    <Toast.Root
      key={toast.id}
      toast={toast}
      className="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]"
    >
      <Toast.Content className="h-full overflow-hidden p-3 transition-opacity duration-250">
        <Toast.Title className="text-sm font-bold" />
        <Toast.Description className="text-sm text-neutral-700 dark:text-neutral-300" />
        <div className="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore>
          <pre className="whitespace-pre-wrap">{JSON.stringify(toast.data, null, 2)}</pre>
        </div>
        <Toast.Close
          className="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700"
          aria-label="Close"
        >
          <XIcon />
        </Toast.Close>
      </Toast.Content>
    </Toast.Root>
  ));
}

export function ToastProvider(props: { children: React.ReactNode }) {
  return (
    <Toast.Provider limit={1}>
      {props.children}
      <Toast.Portal>
        <Toast.Viewport className="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]">
          <Toasts />
        </Toast.Viewport>
      </Toast.Portal>
    </Toast.Provider>
  );
}

export const useToastManager = Toast.useToastManager;

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m2.5 2.5 11 11m-11 0 11-11" />
    </svg>
  );
}
```

```tsx
/* autocomplete.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Autocomplete } from '@base-ui/react/autocomplete';

export function Root(props: Autocomplete.Root.Props<any>) {
  return <Autocomplete.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Autocomplete.Input.Props>(function Input(
  { className, ...props }: Autocomplete.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Autocomplete.Input
      ref={forwardedRef}
      className={clsx(
        'h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Portal(props: Autocomplete.Portal.Props) {
  return <Autocomplete.Portal {...props} />;
}

export function Positioner({ className, ...props }: Autocomplete.Positioner.Props) {
  return <Autocomplete.Positioner className={clsx('outline-none data-empty:hidden', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Autocomplete.Popup.Props) {
  return (
    <Autocomplete.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Autocomplete.List.Props) {
  return (
    <Autocomplete.List
      className={clsx('max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Autocomplete.Item.Props) {
  return (
    <Autocomplete.Item
      className={clsx(
        'flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Checkbox } from '@base-ui/react/checkbox';

export function Root({ className, ...props }: Checkbox.Root.Props) {
  return (
    <Checkbox.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Checkbox.Indicator.Props) {
  return <Checkbox.Indicator className={clsx('flex data-unchecked:hidden', className)} {...props} />;
}
```

```tsx
/* combobox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Combobox } from '@base-ui/react/combobox';

export function Root(props: Combobox.Root.Props<any, any>) {
  return <Combobox.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Combobox.Input.Props>(function Input(
  { className, ...props }: Combobox.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Combobox.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function InputGroup({ className, ...props }: Combobox.InputGroup.Props) {
  return (
    <Combobox.InputGroup
      className={clsx(
        'relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>input]:pr-[2.5rem] has-[.combobox-clear]:[&>input]:pr-[calc(0.5rem+2rem*2)]',
        className,
      )}
      {...props}
    />
  );
}

export function Clear({ className, ...props }: Combobox.Clear.Props) {
  return (
    <Combobox.Clear
      className={clsx('combobox-clear flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)}
      {...props}
    >
      <XIcon />
    </Combobox.Clear>
  );
}

export function Trigger({ className, ...props }: Combobox.Trigger.Props) {
  return <Combobox.Trigger className={clsx('flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Portal(props: Combobox.Portal.Props) {
  return <Combobox.Portal {...props} />;
}

export function Positioner({ className, ...props }: Combobox.Positioner.Props) {
  return <Combobox.Positioner className={clsx('outline-none', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Combobox.Popup.Props) {
  return (
    <Combobox.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function Empty({ className, children, ...props }: Combobox.Empty.Props) {
  return (
    <Combobox.Empty {...props}>
      {children ? <div className={clsx('py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400', className)}>{children}</div> : null}
    </Combobox.Empty>
  );
}

export function List({ className, ...props }: Combobox.List.Props) {
  return (
    <Combobox.List
      className={clsx('outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Combobox.Item.Props) {
  return (
    <Combobox.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Combobox.ItemIndicator.Props) {
  return <Combobox.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function CaretDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M12 6H4l4 4.5z" />
    </svg>
  );
}

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m4.5 4.5 7 7m-7 0 7-7" />
    </svg>
  );
}
```

```tsx
/* field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Field } from '@base-ui/react/field';

export function Root({ className, ...props }: Field.Root.Props) {
  return <Field.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Label({ className, ...props }: Field.Label.Props) {
  return (
    <Field.Label
      className={clsx(
        'text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white',
        className,
      )}
      {...props}
    />
  );
}

export function Description({ className, ...props }: Field.Description.Props) {
  return <Field.Description className={clsx('text-sm text-neutral-600 dark:text-neutral-400', className)} {...props} />;
}

export const Control = React.forwardRef<HTMLInputElement, Field.Control.Props>(function FieldControl(
  { className, ...props }: Field.Control.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Field.Control
      ref={forwardedRef}
      className={clsx(
        'h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Error({ className, ...props }: Field.Error.Props) {
  return <Field.Error className={clsx('text-sm text-red-700 dark:text-red-400', className)} {...props} />;
}

export function Item(props: Field.Item.Props) {
  return <Field.Item {...props} />;
}
```

```tsx
/* fieldset.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Fieldset } from '@base-ui/react/fieldset';

export function Root(props: Fieldset.Root.Props) {
  return <Fieldset.Root {...props} />;
}

export function Legend({ className, ...props }: Fieldset.Legend.Props) {
  return <Fieldset.Legend className={clsx('text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* number-field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { NumberField } from '@base-ui/react/number-field';

export function Root({ className, ...props }: NumberField.Root.Props) {
  return <NumberField.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Group({ className, ...props }: NumberField.Group.Props) {
  return <NumberField.Group className={clsx('flex h-8', className)} {...props} />;
}

export function Decrement({ className, ...props }: NumberField.Decrement.Props) {
  return (
    <NumberField.Decrement
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}

export const Input = React.forwardRef<HTMLInputElement, NumberField.Input.Props>(function Input(
  { className, ...props }: NumberField.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <NumberField.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white',
        className,
      )}
      {...props}
    />
  );
});

export function Increment({ className, ...props }: NumberField.Increment.Props) {
  return (
    <NumberField.Increment
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* radio.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Radio } from '@base-ui/react/radio';

export function Root({ className, ...props }: Radio.Root.Props) {
  return (
    <Radio.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Radio.Indicator.Props) {
  return <Radio.Indicator className={clsx('flex items-center justify-center data-unchecked:hidden before:size-2 before:rounded-full before:bg-current', className)} {...props} />;
}
```

```tsx
/* select.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Select } from '@base-ui/react/select';

export function Root(props: Select.Root.Props<any>) {
  return <Select.Root {...props} />;
}

export function Label({ className, ...props }: Select.Label.Props) {
  return <Select.Label className={clsx('cursor-default text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Trigger({ className, ...props }: Select.Trigger.Props) {
  return (
    <Select.Trigger
      className={clsx(
        'flex h-8 min-w-40 cursor-default items-center justify-between gap-3 border border-neutral-950 bg-white pl-2 pr-1 text-sm font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 data-pressed:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:data-pressed:bg-neutral-800',
        className,
      )}
      {...props}
    />
  );
}

export function Value({ className, ...props }: Select.Value.Props) {
  return <Select.Value className={clsx('data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400', className)} {...props} />;
}

export function Icon(props: Select.Icon.Props) {
  return <Select.Icon {...props} />;
}

export function Portal(props: Select.Portal.Props) {
  return <Select.Portal {...props} />;
}

export function Positioner({ className, ...props }: Select.Positioner.Props) {
  return <Select.Positioner className={clsx('outline-none select-none z-10', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Select.Popup.Props) {
  return (
    <Select.Popup
      className={clsx(
        'group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function ScrollUpArrow({ className, ...props }: Select.ScrollUpArrow.Props) {
  return (
    <Select.ScrollUpArrow
      className={clsx(
        "top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function ScrollDownArrow({ className, ...props }: Select.ScrollDownArrow.Props) {
  return (
    <Select.ScrollDownArrow
      className={clsx(
        "bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Select.List.Props) {
  return <Select.List className={clsx('relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6', className)} {...props} />;
}

export function Item({ className, ...props }: Select.Item.Props) {
  return (
    <Select.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Select.ItemIndicator.Props) {
  return <Select.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function ItemText({ className, ...props }: Select.ItemText.Props) {
  return <Select.ItemText className={clsx('col-start-2', className)} {...props} />;
}
```

```tsx
/* slider.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Slider } from '@base-ui/react/slider';

export function Root({ className, ...props }: Slider.Root.Props<any>) {
  return <Slider.Root className={clsx('grid grid-cols-2', className)} {...props} />;
}

export function Value({ className, ...props }: Slider.Value.Props) {
  return <Slider.Value className={clsx('text-sm font-normal text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Control({ className, ...props }: Slider.Control.Props) {
  return <Slider.Control className={clsx('flex col-span-2 touch-none items-center py-3 select-none', className)} {...props} />;
}

export function Track({ className, ...props }: Slider.Track.Props) {
  return <Slider.Track className={clsx('h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800', className)} {...props} />;
}

export function Indicator({ className, ...props }: Slider.Indicator.Props) {
  return <Slider.Indicator className={clsx('bg-neutral-950 select-none dark:bg-white', className)} {...props} />;
}

export function Thumb({ className, ...props }: Slider.Thumb.Props) {
  return (
    <Slider.Thumb
      className={clsx(
        'size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* switch.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Switch } from '@base-ui/react/switch';

export function Root({ className, ...props }: Switch.Root.Props) {
  return (
    <Switch.Root
      className={clsx(
        'flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function Thumb({ className, ...props }: Switch.Thumb.Props) {
  return (
    <Switch.Thumb
      className={clsx(
        'size-3.5 bg-neutral-950 transition-[translate,background-color] duration-150 ease-[ease] data-checked:translate-x-4 data-checked:bg-white dark:bg-white dark:data-checked:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```ts
/* stencil-form-events.ts */
import type { FormElements, FormValues } from './stencil-form';

export interface FieldState {
  value: FormValues[keyof FormValues];
  invalid: boolean;
  touched: boolean;
  dirty: boolean;
  error?: string;
}

/** The form library owns values and validation; the elements own their UI and ARIA. */
export function connectField(elements: FormElements, name: keyof FormValues, onChange: (value: any) => void, onBlur: () => void, inputRef?: (element: HTMLElement | null) => void) {
  const field = elements.fields[name];
  const control = elements.controls[name];
  const refTarget = name === 'scalingThreshold' ? field.querySelector('fs-slider-thumb')! : name === 'allowedNetworkProtocols' ? field.querySelector('fs-checkbox-root')! : control;
  const error = elements.errors[name];
  // Keep the authored text node: Field.Error can be offline while valid.
  const message = error?.querySelector('span');
  const valueProperty = name === 'restartOnFailure' ? 'checked' : 'value';
  const eventName = name === 'restartOnFailure' ? 'checkedChange' : 'valueChange';
  const change = (event: Event) => {
    if (event.target === control) onChange((event as CustomEvent).detail[valueProperty]);
  };
  control.addEventListener(eventName, change);
  if (name === 'scalingThreshold') control.addEventListener('valueCommitted', change);
  const blur = () => onBlur();
  field.addEventListener('focusout', blur);
  if (inputRef) {
    if (name === 'numOfInstances') inputRef(field.querySelector('fs-number-field-input'));
    else Reflect.set(refTarget, 'inputRef', inputRef);
  }
  return {
    update(state: FieldState) {
      Reflect.set(control, valueProperty, state.value);
      field.invalid = state.invalid;
      field.touched = state.touched;
      field.dirty = state.dirty;
      if (message) message.textContent = state.error ?? '';
      if (error) error.match = state.invalid;
    },
    destroy() {
      control.removeEventListener(eventName, change);
      control.removeEventListener('valueCommitted', change);
      field.removeEventListener('focusout', blur);
      if (inputRef) {
        Reflect.set(refTarget, 'inputRef', undefined);
        inputRef(null);
      }
    },
  };
}
```

```ts
/* stencil-toast.ts */
import { createToastManager, type ToastObject } from 'finesoft-components/toast';
import type { Components } from 'finesoft-components';

const toastHTML = `
<fs-toast-root class="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]">
  <fs-toast-content class="h-full overflow-hidden p-3 transition-opacity duration-250">
    <fs-toast-title class="text-sm font-bold"></fs-toast-title>
    <fs-toast-description class="text-sm text-neutral-700 dark:text-neutral-300"></fs-toast-description>
    <div class="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore="true">
      <pre class="whitespace-pre-wrap"></pre>
    </div>
    <fs-toast-close class="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700" aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

const themedToastHTML = `
<fs-toast-root data-fs-variant="rich">
  <fs-toast-content>
    <fs-toast-title></fs-toast-title>
    <fs-toast-description></fs-toast-description>
    <div class="handbook-form-submitted-values" data-base-ui-swipe-ignore="true">
      <pre></pre>
    </div>
    <fs-toast-close aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

export function connectToasts(provider: HTMLElement & Components.FsToastProvider, viewport: Element, themed = false) {
  const manager = createToastManager();
  const roots = new Map<string, HTMLElement & Components.FsToastRoot>();
  function update(event: CustomEvent<ToastObject[]>) {
    const toasts = event.detail;
    for (const [id, root] of roots) {
      if (!toasts.some(toast => toast.id === id)) {
        root.remove();
        roots.delete(id);
      }
    }
    for (const toast of toasts) {
      let root = roots.get(toast.id);
      if (!root) {
        const template = provider.ownerDocument.createElement('template');
        template.innerHTML = themed ? themedToastHTML : toastHTML;
        root = template.content.firstElementChild as HTMLElement & Components.FsToastRoot;
        root.toast = toast;
        root.querySelector('pre')!.textContent = JSON.stringify(toast.data, null, 2);
        roots.set(toast.id, root);
        viewport.append(root);
      } else {
        root.toast = toast;
      }
    }
  }
  provider.addEventListener('toastsChange', update as EventListener);
  provider.toastManager = manager;
  return {
    submit: (data: unknown) => manager.add({ title: 'Form submitted', description: 'The form contains these values:', data: data as Record<string, unknown> }),
    destroy: () => provider.removeEventListener('toastsChange', update as EventListener),
  };
}
```

### Initialize the form

Initialize the form with the `useForm` hook, assigning the initial value of each field by their name in the `defaultValues` parameter:

```tsx title="Initialize a form instance"
import { useForm } from 'react-hook-form';

const { control, handleSubmit } = useForm<FormValues>({
  defaultValues: {
    username: '',
    email: '',
  },
});
```

### Integrate components

Use the `<Controller>` component to integrate with any `<Field>` component, forwarding the `name`, `field`, and `fieldState` render props to the appropriate part:

```tsx title="Integrating the controller component with Base UI field"
import { useForm, Controller } from "react-hook-form";
import { Field } from '@base-ui/react/field';

const { control, handleSubmit} = useForm({
  defaultValues: {
    username: '',
  }
})

<Controller
  {/* @highlight-start */}
  name="username"
  control={control}
  render={({
    // @highlight-text "ref" "value" "onBlur" "onChange"
    field: { name, ref, value, onBlur, onChange },
    // @highlight-text "invalid" "isTouched" "isDirty" "error"
    fieldState: { invalid, isTouched, isDirty, error },
  }) => (
    {/* @highlight-text "invalid" "isTouched" "isDirty" */}
    <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
    {/* @highlight-end */}
      <Field.Label>Username</Field.Label>
      <Field.Description>
        May appear where you contribute or are mentioned. You can remove it at any time.
      </Field.Description>
      {/* @highlight-start */}
      <Field.Control
        placeholder="e.g. alice132"
        value={value} {/* @highlight-text "value" */}
        onBlur={onBlur} {/* @highlight-text "onBlur" */}
        onValueChange={onChange} {/* @highlight-text "onChange" */}
        ref={ref} {/* @highlight-text "ref" */}
      />
      {/* @highlight-end */}
      <Field.Error match={!!error}> {/* @highlight-text "error" */}
        {error?.message} {/* @highlight-text "error" */}
      </Field.Error>
    </Field.Root>
  )}
/>
```

For React Hook Form to focus invalid fields when performing validation, you must ensure that any wrapping components forward the `ref` to the underlying Base UI component. You can typically accomplish this using the `inputRef` prop, or directly as the `ref` for components that render an input element like `<NumberField.Input>`.

### Field validation

Specify `rules` on the `<Controller>` in the same format as [`register`](https://react-hook-form.com/docs/useform/register) options, and use the `match` prop to delegate control of the error rendering:

```tsx title="Defining validation rules and displaying errors"
import { Controller } from "react-hook-form";
import { Field } from '@base-ui/react/field';

<Controller
  {/* @highlight-start */}
  name="username"
  control={control}
  rules={{
    required: 'This is a required field',
    minLength: { value: 2, message: 'Too short' },
    validate: (value) => {
      if (/* custom logic */) {
        return 'Invalid'
      }
      return null;
    },
    {/* @highlight-end */}
  }}
  render={({
    field: { name, ref, value, onBlur, onChange },
    fieldState: { invalid, isTouched, isDirty, error },
  }) => (
    <Field.Root name={name} invalid={invalid} touched={isTouched} dirty={isDirty}>
      <Field.Label>Username</Field.Label>
      <Field.Description>
        May appear where you contribute or are mentioned. You can remove it at any time.
      </Field.Description>
      <Field.Control
        placeholder="e.g. alice132"
        value={value}
        onBlur={onBlur}
        onValueChange={onChange}
        ref={ref}
      />
      {/* @highlight-start */}
      <Field.Error match={!!error}>
        {error?.message}
      </Field.Error>
      {/* @highlight-end */}
    </Field.Root>
  )}
/>
```

### Submitting data

Wrap your submit handler function with `handleSubmit` to receive the form values as a JavaScript object for further handling:

```tsx title="Form submission handler"
import { useForm } from 'react-hook-form';
import { Form } from '@base-ui/react/form';

interface FormValues {
  username: string;
  email: string;
}

const { handleSubmit } = useForm<FormValues>();

async function submitForm(data: FormValues) {
  // transform the object and/or submit it to a server
  await fetch(/* ... */);
}

<Form onSubmit={handleSubmit(submitForm)} />;
```

## TanStack Form

[TanStack Form](https://tanstack.com/form/v1/docs/overview) is a form library with a function-based API for orchestrating validations that can also be integrated with Base UI.

## Demo

### Component theme

The Stencil example uses the built-in component theme. The frozen React comparison retains its original Tailwind styling.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactExample from './react-tanstack-form';
import StencilExample from './docs-themed-preview';
import { formHTML, configureForm } from './stencil-form';

export default function Comparison() {
  const options = { themed: true, externalValidation: true, nativeForm: true };
  return (
    <StencilComparison
      component="handbook-form-tanstack-form"
      react={<ReactExample />}
      stencil={null}
      renderSource={() => formHTML(options)}
      beforeHydrate={document => configureForm(document, options)}
      clientStencil={<StencilExample />}
    />
  );
}
```

```tsx
/* react-tanstack-form.tsx */
'use client';
import * as React from 'react';
import { useForm, revalidateLogic, DeepKeys, ValidationError } from '@tanstack/react-form';
import { Button } from './button';
import { CheckboxGroup } from './checkbox-group';
import { RadioGroup } from './radio-group';
import { ToastProvider, useToastManager } from './toast';
import * as Autocomplete from './autocomplete';
import * as Checkbox from './checkbox';
import * as Combobox from './combobox';
import * as Field from './field';
import * as Fieldset from './fieldset';
import * as NumberField from './number-field';
import * as Radio from './radio';
import * as Select from './select';
import * as Slider from './slider';
import * as Switch from './switch';

interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};

function TanstackForm() {
  const toastManager = useToastManager();

  const form = useForm({
    defaultValues,
    onSubmit: ({ value: formValues }) => {
      toastManager.add({
        title: 'Form submitted',
        description: 'The form contains these values:',
        data: formValues,
      });
    },
    validationLogic: revalidateLogic({
      mode: 'submit',
      modeAfterSubmission: 'change',
    }),
    validators: {
      onDynamic: ({ value: formValues }) => {
        const errors: Partial<Record<DeepKeys<FormValues>, ValidationError>> = {};

        (['serverName', 'region', 'containerImage', 'serverType', 'numOfInstances'] as const).forEach(requiredField => {
          if (!formValues[requiredField]) {
            errors[requiredField] = 'This is a required field.';
          }
        });

        if (formValues.serverName && formValues.serverName.length < 3) {
          errors.serverName = 'At least 3 characters.';
        }

        return isEmpty(errors) ? undefined : { form: errors, fields: errors };
      },
    },
  });

  /* eslint-disable react/no-children-prop */
  return (
    <form
      aria-label="Launch new cloud server"
      className="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]"
      noValidate
      onSubmit={event => {
        event.preventDefault();
        form.handleSubmit();
      }}
    >
      <form.Field
        name="serverName"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Field.Label>Server name</Field.Label>
              <Field.Control value={field.state.value} onValueChange={field.handleChange} onBlur={field.handleBlur} placeholder="e.g. api-server-01" />
              <Field.Description>Must be 3 or more characters long</Field.Description>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="region"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Combobox.Root items={REGIONS} value={field.state.value} onValueChange={field.handleChange}>
                <div className="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
                  <Field.Label className="mb-1 block">Region</Field.Label>
                  <Combobox.InputGroup>
                    <Combobox.Input placeholder="e.g. eu-central-1" onBlur={field.handleBlur} />
                    <div className="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
                      <Combobox.Clear />
                      <Combobox.Trigger>
                        <Combobox.CaretDownIcon />
                      </Combobox.Trigger>
                    </div>
                  </Combobox.InputGroup>
                </div>
                <Combobox.Portal>
                  <Combobox.Positioner>
                    <Combobox.Popup>
                      <Combobox.Empty>No matches</Combobox.Empty>
                      <Combobox.List>
                        {(region: string) => {
                          return (
                            <Combobox.Item key={region} value={region}>
                              <Combobox.ItemIndicator>
                                <CheckIcon />
                              </Combobox.ItemIndicator>
                              <span className="col-start-2">{region}</span>
                            </Combobox.Item>
                          );
                        }}
                      </Combobox.List>
                    </Combobox.Popup>
                  </Combobox.Positioner>
                </Combobox.Portal>
              </Combobox.Root>

              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="containerImage"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Autocomplete.Root items={IMAGES} mode="both" value={field.state.value} onValueChange={field.handleChange} itemToStringValue={(itemValue: Image) => itemValue.url}>
                <Field.Label>Container image</Field.Label>
                <Autocomplete.Input placeholder="e.g. docker.io/library/node:latest" onBlur={field.handleBlur} />
                <Field.Description>Enter a registry URL with optional tags</Field.Description>
                <Autocomplete.Portal>
                  <Autocomplete.Positioner>
                    <Autocomplete.Popup>
                      <Autocomplete.List>
                        {(image: Image) => {
                          return (
                            <Autocomplete.Item key={image.url} value={image}>
                              <span>{image.name}</span>
                              <span className="font-mono whitespace-nowrap text-xs opacity-80">{image.url}</span>
                            </Autocomplete.Item>
                          );
                        }}
                      </Autocomplete.List>
                    </Autocomplete.Popup>
                  </Autocomplete.Positioner>
                </Autocomplete.Portal>
              </Autocomplete.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="serverType"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Select.Root items={SERVER_TYPES} value={field.state.value} onValueChange={field.handleChange}>
                <div className="w-fit space-y-1">
                  <Select.Label>Server type</Select.Label>
                  <Select.Trigger className="w-48" onBlur={field.handleBlur}>
                    <Select.Value />
                    <Select.Icon>
                      <CaretUpDownIcon />
                    </Select.Icon>
                  </Select.Trigger>
                </div>
                <Select.Portal>
                  <Select.Positioner>
                    <Select.Popup>
                      <Select.ScrollUpArrow />
                      <Select.List>
                        {SERVER_TYPES.map(({ label, value }) => {
                          return (
                            <Select.Item key={value} value={value}>
                              <Select.ItemIndicator>
                                <CheckIcon />
                              </Select.ItemIndicator>
                              <Select.ItemText>{label}</Select.ItemText>
                            </Select.Item>
                          );
                        })}
                      </Select.List>
                      <Select.ScrollDownArrow />
                    </Select.Popup>
                  </Select.Positioner>
                </Select.Portal>
              </Select.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="numOfInstances"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <NumberField.Root value={field.state.value} onValueChange={field.handleChange} min={1} max={64}>
                <Field.Label>Number of instances</Field.Label>
                <NumberField.Group>
                  <NumberField.Decrement>
                    <MinusIcon />
                  </NumberField.Decrement>
                  <NumberField.Input onBlur={field.handleBlur} />
                  <NumberField.Increment>
                    <PlusIcon />
                  </NumberField.Increment>
                </NumberField.Group>
              </NumberField.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="scalingThreshold"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Fieldset.Root
                render={
                  <Slider.Root
                    value={field.state.value}
                    onValueChange={field.handleChange}
                    onValueCommitted={field.handleChange}
                    thumbAlignment="edge"
                    min={0}
                    max={1}
                    step={0.01}
                    format={{
                      style: 'percent',
                      minimumFractionDigits: 0,
                      maximumFractionDigits: 0,
                    }}
                    className="w-full gap-y-2"
                  />
                }
              >
                <Fieldset.Legend>Scaling threshold</Fieldset.Legend>
                <Slider.Value className="col-start-2 text-end" />
                <Slider.Control>
                  <Slider.Track>
                    <Slider.Indicator />
                    <Slider.Thumb index={0} aria-label="Minimum threshold" onBlur={field.handleBlur} />
                    <Slider.Thumb index={1} aria-label="Maximum threshold" onBlur={field.handleBlur} />
                  </Slider.Track>
                </Slider.Control>
              </Fieldset.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="storageType"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Fieldset.Root render={<RadioGroup value={field.state.value} onValueChange={field.handleChange} className="gap-4" />}>
                <Fieldset.Legend className="-mt-px">Storage type</Fieldset.Legend>
                {['ssd', 'hdd'].map(radioValue => (
                  <Field.Item key={radioValue}>
                    <Field.Label className="uppercase">
                      <Radio.Root value={radioValue}>
                        <Radio.Indicator />
                      </Radio.Root>
                      {radioValue}
                    </Field.Label>
                  </Field.Item>
                ))}
              </Fieldset.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="restartOnFailure"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Field.Label className="gap-2">
                Restart on failure
                <Switch.Root checked={field.state.value} onCheckedChange={field.handleChange} onBlur={field.handleBlur}>
                  <Switch.Thumb />
                </Switch.Root>
              </Field.Label>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="allowedNetworkProtocols"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Fieldset.Root render={<CheckboxGroup value={field.state.value} onValueChange={field.handleChange} />}>
                <Fieldset.Legend className="mb-2">Allowed network protocols</Fieldset.Legend>
                <div className="flex gap-4">
                  {['http', 'https', 'ssh'].map(checkboxValue => {
                    return (
                      <Field.Item key={checkboxValue}>
                        <Field.Label className="uppercase">
                          <Checkbox.Root value={checkboxValue} onBlur={field.handleBlur}>
                            <Checkbox.Indicator>
                              <CheckIcon />
                            </Checkbox.Indicator>
                          </Checkbox.Root>
                          {checkboxValue}
                        </Field.Label>
                      </Field.Item>
                    );
                  })}
                </div>
              </Fieldset.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <Button type="submit" className="mt-3">
        Launch server
      </Button>
    </form>
  );
}

export default function App() {
  return (
    <ToastProvider>
      <TanstackForm />
    </ToastProvider>
  );
}

function CaretUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="m2.5 8.5 4 4 7-9" />
    </svg>
  );
}

function PlusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13M8 14.5v-13" />
    </svg>
  );
}

function MinusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13" />
    </svg>
  );
}

function isEmpty(object: Partial<Record<DeepKeys<FormValues>, ValidationError>>) {
  // eslint-disable-next-line
  for (const _ in object) {
    return false;
  }
  return true;
}

function cartesian<T extends string[][]>(...arrays: T): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}

const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));

interface Image {
  url: string;
  name: string;
}
/* prettier-ignore */
const IMAGES: Image[] = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map((name) => ({
  url: `docker.io/library/${name}`,
  name,
}));

const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];
```

```tsx
/* docs-themed-preview.tsx */
'use client';
import { NativeStencilPreview } from 'docs/src/components/NativeStencilPreview';
import { mount } from './stencil-themed-tanstack-form';
export default function Preview() {
  return <NativeStencilPreview mount={mount} />;
}
```

```ts
/* stencil-form.ts */
import type { Components } from 'finesoft-components';

export interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

export const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};
export const fieldNames = Object.keys(defaultValues) as Array<keyof FormValues>;
export interface FormOptions {
  externalValidation?: boolean;
  nativeForm?: boolean;
  themed?: boolean;
}

function cartesian(...arrays: string[][]): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}
const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));
const IMAGES = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map(name => ({ name, url: `docker.io/library/${name}` }));
const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];

// This same Web Components declaration is used by the browser and by Stencil SSR.
// The framework integrations below only exchange public properties and events.
export function formHTML(options: FormOptions = {}): string {
  if (options.themed) return themedFormHTML(options);
  const { nativeForm = false } = options;
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]" aria-label="Launch new cloud server">
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverName">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Server name</fs-field-label>
      <fs-field-control class="h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Must be 3 or more characters long</fs-field-description>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="region">
      <fs-combobox-root required="">
        <div class="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
          <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white mb-1 block'>Region</fs-field-label>
          <fs-combobox-input-group class="relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>fs-combobox-input>input]:pr-[2.5rem] has-[.combobox-clear]:[&>fs-combobox-input>input]:pr-[calc(0.5rem+2rem*2)]">
            <fs-combobox-input class="h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div class="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
              <fs-combobox-clear class="[&::part(clear)]:box-border [&::part(clear)]:m-0 [&::part(clear)]:p-0 [&::part(clear)]:border-solid [&::part(clear)]:[font-family:inherit] [&::part(clear)]:[font-size:inherit] [&::part(clear)]:[font-weight:inherit] [&::part(clear)]:[line-height:inherit] combobox-clear [&::part(clear)]:flex [&::part(clear)]:h-full [&::part(clear)]:w-6 [&::part(clear)]:items-center [&::part(clear)]:justify-center [&::part(clear)]:border-0 [&::part(clear)]:bg-transparent [&::part(clear)]:p-0 [&::part(clear)]:text-neutral-950 dark:[&::part(clear)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:p-0 [&::part(trigger)]:border-solid [&::part(trigger)]:[font-family:inherit] [&::part(trigger)]:[font-size:inherit] [&::part(trigger)]:[font-weight:inherit] [&::part(trigger)]:[line-height:inherit] [&::part(trigger)]:flex [&::part(trigger)]:h-full [&::part(trigger)]:w-6 [&::part(trigger)]:items-center [&::part(trigger)]:justify-center [&::part(trigger)]:border-0 [&::part(trigger)]:bg-transparent [&::part(trigger)]:p-0 [&::part(trigger)]:text-neutral-950 dark:[&::part(trigger)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner class="outline-none" side-offset="4">
            <fs-combobox-popup class="w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-combobox-empty>
                <div class="py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400">No matches</div>
              </fs-combobox-empty>
              <fs-combobox-list class="outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0">${REGIONS.map(
                region => `
<fs-combobox-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white" value="${region}">
  <fs-combobox-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span class="col-start-2">${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Container image</fs-field-label>
        <fs-autocomplete-input class="h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner class="outline-none data-empty:hidden" side-offset="4">
            <fs-autocomplete-popup class="w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-autocomplete-list class="max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0">${IMAGES.map(
                image => `
<fs-autocomplete-item class="flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white">
  <span>${image.name}</span>
  <span class="font-mono whitespace-nowrap text-xs opacity-80">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverType">
      <fs-select-root required="">
        <div class="w-fit space-y-1">
          <fs-select-label class="cursor-default text-sm font-bold text-neutral-950 dark:text-white">Server type</fs-select-label>
          <fs-select-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:font-[inherit] [&::part(trigger)]:border-solid [&::part(trigger)]:p-0 [&::part(trigger)]:flex [&::part(trigger)]:h-8 [&::part(trigger)]:min-w-40 [&::part(trigger)]:cursor-default [&::part(trigger)]:items-center [&::part(trigger)]:justify-between [&::part(trigger)]:gap-3 [&::part(trigger)]:border [&::part(trigger)]:border-neutral-950 [&::part(trigger)]:bg-white [&::part(trigger)]:pl-2 [&::part(trigger)]:pr-1 [&::part(trigger)]:text-sm [&::part(trigger)]:font-normal [&::part(trigger)]:text-neutral-950 [&::part(trigger)]:select-none not-data-disabled:[&::part(trigger)]:hover:bg-neutral-100 not-data-disabled:[&::part(trigger)]:active:bg-neutral-200 data-disabled:[&::part(trigger)]:border-neutral-500 data-disabled:[&::part(trigger)]:text-neutral-500 data-pressed:[&::part(trigger)]:bg-neutral-100 [&::part(trigger):focus-visible]:outline-2 [&::part(trigger):focus-visible]:-outline-offset-1 [&::part(trigger):focus-visible]:outline-neutral-950 dark:[&::part(trigger):focus-visible]:outline-white dark:[&::part(trigger)]:border-white dark:[&::part(trigger)]:bg-neutral-950 dark:[&::part(trigger)]:text-white dark:not-data-disabled:[&::part(trigger)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(trigger)]:active:bg-neutral-700 dark:data-disabled:[&::part(trigger)]:border-neutral-400 dark:data-disabled:[&::part(trigger)]:text-neutral-400 dark:data-pressed:[&::part(trigger)]:bg-neutral-800 [&::part(trigger)]:w-48">
            <fs-select-value class="data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400"></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner class="outline-none select-none z-10" side-offset="4">
            <fs-select-popup class="group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-select-scroll-up-arrow class="top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950"></fs-select-scroll-up-arrow>
              <fs-select-list class="relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6">${SERVER_TYPES.map(
                item => `
<fs-select-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950">
  <fs-select-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text class="col-start-2">${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow class="bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950"></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="numOfInstances">
      <fs-number-field-root class="flex flex-col items-start gap-1" min="1" max="64" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Number of instances</fs-field-label>
        <fs-number-field-group class="[&::part(group)]:flex [&::part(group)]:h-8">
          <fs-number-field-decrement class="[&::part(decrement)]:box-border [&::part(decrement)]:m-0 [&::part(decrement)]:p-0 [&::part(decrement)]:border-solid [&::part(decrement)]:[font-family:inherit] [&::part(decrement)]:[font-size:inherit] [&::part(decrement)]:[font-weight:inherit] [&::part(decrement)]:[line-height:inherit] [&::part(decrement)]:flex [&::part(decrement)]:h-full [&::part(decrement)]:w-8 [&::part(decrement)]:items-center [&::part(decrement)]:justify-center [&::part(decrement)]:rounded-none [&::part(decrement)]:border [&::part(decrement)]:border-neutral-950 [&::part(decrement)]:bg-white [&::part(decrement)]:bg-clip-padding [&::part(decrement)]:text-neutral-950 [&::part(decrement)]:outline-0 [&::part(decrement)]:select-none not-data-disabled:[&::part(decrement)]:hover:bg-neutral-100 not-data-disabled:[&::part(decrement)]:active:bg-neutral-200 data-disabled:[&::part(decrement)]:border-neutral-500 data-disabled:[&::part(decrement)]:text-neutral-500 [&::part(decrement):focus-visible]:z-1 [&::part(decrement):focus-visible]:outline-2 [&::part(decrement):focus-visible]:-outline-offset-1 [&::part(decrement):focus-visible]:outline-neutral-950 dark:[&::part(decrement):focus-visible]:outline-white dark:[&::part(decrement)]:border-white dark:[&::part(decrement)]:bg-neutral-950 dark:[&::part(decrement)]:text-white dark:not-data-disabled:[&::part(decrement)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(decrement)]:active:bg-neutral-700 dark:data-disabled:[&::part(decrement)]:border-neutral-400 dark:data-disabled:[&::part(decrement)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input class="h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white"></fs-number-field-input>
          <fs-number-field-increment class="[&::part(increment)]:box-border [&::part(increment)]:m-0 [&::part(increment)]:p-0 [&::part(increment)]:border-solid [&::part(increment)]:[font-family:inherit] [&::part(increment)]:[font-size:inherit] [&::part(increment)]:[font-weight:inherit] [&::part(increment)]:[line-height:inherit] [&::part(increment)]:flex [&::part(increment)]:h-full [&::part(increment)]:w-8 [&::part(increment)]:items-center [&::part(increment)]:justify-center [&::part(increment)]:rounded-none [&::part(increment)]:border [&::part(increment)]:border-neutral-950 [&::part(increment)]:bg-white [&::part(increment)]:bg-clip-padding [&::part(increment)]:text-neutral-950 [&::part(increment)]:outline-0 [&::part(increment)]:select-none not-data-disabled:[&::part(increment)]:hover:bg-neutral-100 not-data-disabled:[&::part(increment)]:active:bg-neutral-200 data-disabled:[&::part(increment)]:border-neutral-500 data-disabled:[&::part(increment)]:text-neutral-500 [&::part(increment):focus-visible]:z-1 [&::part(increment):focus-visible]:outline-2 [&::part(increment):focus-visible]:-outline-offset-1 [&::part(increment):focus-visible]:outline-neutral-950 dark:[&::part(increment):focus-visible]:outline-white dark:[&::part(increment)]:border-white dark:[&::part(increment)]:bg-neutral-950 dark:[&::part(increment)]:text-white dark:not-data-disabled:[&::part(increment)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(increment)]:active:bg-neutral-700 dark:data-disabled:[&::part(increment)]:border-neutral-400 dark:data-disabled:[&::part(increment)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="scalingThreshold">
        <fs-slider-root class="grid grid-cols-2 w-full gap-y-2" thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label class="text-sm font-bold text-neutral-950 dark:text-white">Scaling threshold</fs-slider-label>
          <fs-slider-value class="text-sm font-normal text-neutral-950 dark:text-white col-start-2 text-end"></fs-slider-value>
          <fs-slider-control class="flex col-span-2 touch-none items-center py-3 select-none">
            <fs-slider-track class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
              <fs-slider-indicator class="bg-neutral-950 select-none dark:bg-white"></fs-slider-indicator>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="storageType">
        <fs-radio-group aria-label="Storage type" class="flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white gap-4" default-value="ssd">
          <div class="text-sm font-bold text-neutral-950 dark:text-white -mt-px">Storage type</div>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'ssd' : 'SSD'}
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="hdd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'hdd' : 'HDD'}
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="restartOnFailure">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white gap-2'>
        Restart on failure
        <fs-switch-root class="flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white" default-checked="">
          <fs-switch-thumb class="[&::part(thumb)]:size-3.5 [&::part(thumb)]:bg-neutral-950 [&::part(thumb)]:transition-[translate,background-color] [&::part(thumb)]:duration-150 [&::part(thumb)]:ease-[ease] data-checked:[&::part(thumb)]:translate-x-4 data-checked:[&::part(thumb)]:bg-white dark:[&::part(thumb)]:bg-white dark:data-checked:[&::part(thumb)]:bg-neutral-950"></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols" class="flex flex-col items-start gap-1 text-neutral-950 dark:text-white">
          <div class="text-sm font-bold text-neutral-950 dark:text-white mb-2">Allowed network protocols</div>
          <div class="flex gap-4">
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="http">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="https">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssh">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button type="submit" class="[&::part(control)]:p-0 [&::part(control)]:flex [&::part(control)]:h-8 [&::part(control)]:items-center [&::part(control)]:justify-center [&::part(control)]:gap-2 [&::part(control)]:rounded-none [&::part(control)]:border [&::part(control)]:border-neutral-950 [&::part(control)]:bg-white [&::part(control)]:px-3 [&::part(control)]:py-0 [&::part(control)]:[font-family:inherit] [&::part(control)]:text-sm [&::part(control)]:leading-none [&::part(control)]:whitespace-nowrap [&::part(control)]:font-normal [&::part(control)]:text-neutral-950 [&::part(control)]:select-none not-data-disabled:[&::part(control)]:hover:bg-neutral-100 not-data-disabled:[&::part(control)]:active:bg-neutral-200 data-disabled:[&::part(control)]:border-neutral-500 data-disabled:[&::part(control)]:text-neutral-500 disabled:[&::part(control)]:border-neutral-500 disabled:[&::part(control)]:text-neutral-500 [&::part(control):focus-visible]:outline-2 [&::part(control):focus-visible]:-outline-offset-1 [&::part(control):focus-visible]:outline-neutral-950 dark:[&::part(control):focus-visible]:outline-white dark:[&::part(control)]:border-white dark:[&::part(control)]:bg-neutral-950 dark:[&::part(control)]:text-white dark:not-data-disabled:[&::part(control)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(control)]:active:bg-neutral-700 dark:data-disabled:[&::part(control)]:border-neutral-400 dark:data-disabled:[&::part(control)]:text-neutral-400 dark:disabled:[&::part(control)]:border-neutral-400 dark:disabled:[&::part(control)]:text-neutral-400 [&::part(control)]:mt-3">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

function themedFormHTML({ nativeForm = false }: FormOptions = {}): string {
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="handbook-form" aria-label="Launch new cloud server">
    <fs-field-root name="serverName">
      <fs-field-label>Server name</fs-field-label>
      <fs-field-control default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description>Must be 3 or more characters long</fs-field-description>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="region">
      <fs-combobox-root required="">
        <div>
          <fs-field-label>Region</fs-field-label>
          <fs-combobox-input-group>
            <fs-combobox-input placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div>
              <fs-combobox-clear>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner side-offset="4">
            <fs-combobox-popup>
              <fs-combobox-empty><div>No matches</div></fs-combobox-empty>
              <fs-combobox-list>${REGIONS.map(
                region => `
<fs-combobox-item value="${region}">
  <fs-combobox-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span>${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label>Container image</fs-field-label>
        <fs-autocomplete-input placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description>Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner data-fs-variant="hide-empty" side-offset="4">
            <fs-autocomplete-popup>
              <fs-autocomplete-list>${IMAGES.map(
                image => `
<fs-autocomplete-item data-fs-variant="stacked">
  <span>${image.name}</span>
  <span class="handbook-form-image-url">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="serverType">
      <fs-select-root required="">
        <div class="handbook-form-select">
          <fs-select-label>Server type</fs-select-label>
          <fs-select-trigger>
            <fs-select-value></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner side-offset="4">
            <fs-select-popup>
              <fs-select-scroll-up-arrow></fs-select-scroll-up-arrow>
              <fs-select-list>${SERVER_TYPES.map(
                item => `
<fs-select-item>
  <fs-select-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text>${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="numOfInstances">
      <fs-number-field-root min="1" max="64" required="">
        <fs-field-label>Number of instances</fs-field-label>
        <fs-number-field-group data-fs-variant="segmented">
          <fs-number-field-decrement>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input></fs-number-field-input>
          <fs-number-field-increment>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="scalingThreshold">
        <fs-slider-root thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label>Scaling threshold</fs-slider-label>
          <fs-slider-value></fs-slider-value>
          <fs-slider-control>
            <fs-slider-track>
              <fs-slider-indicator></fs-slider-indicator>
              <fs-slider-thumb index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root name="storageType">
        <fs-radio-group data-fs-variant="horizontal" aria-label="Storage type" default-value="ssd">
          <div class="handbook-form-group-label">Storage type</div>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="ssd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              SSD
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="hdd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              HDD
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root name="restartOnFailure">
      <fs-field-label>
        Restart on failure
        <fs-switch-root default-checked="">
          <fs-switch-thumb></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols">
          <div class="handbook-form-group-label handbook-form-protocol-heading">Allowed network protocols</div>
          <div class="handbook-form-protocols">
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="http">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="https">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="ssh">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button class="handbook-form-submit" type="submit">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="handbook-form-toast-viewport"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

export function configureForm(scope: ParentNode, { externalValidation = false }: FormOptions = {}) {
  const combobox = scope.querySelector('fs-combobox-root') as HTMLElement & Components.FsComboboxRoot;
  combobox.items = REGIONS;
  const autocomplete = scope.querySelector('fs-autocomplete-root') as HTMLElement & Components.FsAutocompleteRoot;
  autocomplete.items = IMAGES;
  autocomplete.itemToStringValue = (item: (typeof IMAGES)[number]) => item.url;
  scope.querySelectorAll('fs-autocomplete-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsAutocompleteItem).value = IMAGES[index];
  });
  (scope.querySelector('fs-select-root') as HTMLElement & Components.FsSelectRoot).items = SERVER_TYPES;
  scope.querySelectorAll('fs-select-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsSelectItem).value = SERVER_TYPES[index].value;
  });
  Object.assign(scope.querySelector('fs-slider-root')!, {
    defaultValue: [0.2, 0.8],
    format: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0 },
  });
  (scope.querySelector('fs-checkbox-group') as HTMLElement & Components.FsCheckboxGroup).defaultValue = [];
  if (externalValidation) {
    scope.querySelectorAll('[required], [minlength], [pattern]').forEach(element => {
      for (const name of ['required', 'minlength', 'pattern']) element.removeAttribute(name);
    });
    scope.querySelectorAll('fs-field-root').forEach(element => Object.assign(element, { invalid: false, touched: false, dirty: false }));
    scope.querySelectorAll('fs-field-error').forEach(element => {
      (element as HTMLElement & Components.FsFieldError).match = false;
      element.append(element.ownerDocument.createElement('span'));
    });
  }
  scope.querySelector('form')?.setAttribute('novalidate', '');
}

export function createForm(container: HTMLElement, options: FormOptions = {}) {
  const template = container.ownerDocument.createElement('template');
  template.innerHTML = formHTML(options);
  const content = template.content;
  // Arrays, item objects and callbacks are properties, not JSON attributes.
  // Set them before connecting the elements, including the initially offline Portal parts.
  configureForm(content, options);
  const provider = content.querySelector('fs-toast-provider') as HTMLElement & Components.FsToastProvider;
  const form = content.querySelector('fs-form, form') as HTMLElement & Components.FsForm;
  const fields = Object.fromEntries(fieldNames.map(name => [name, content.querySelector(`fs-field-root[name="${name}"]`)!])) as Record<
    keyof FormValues,
    HTMLElement & Components.FsFieldRoot
  >;
  const controls = Object.fromEntries(
    fieldNames.map(name => [
      name,
      fields[name].querySelector(
        'fs-field-control, fs-combobox-root, fs-autocomplete-root, fs-select-root, fs-number-field-root, fs-slider-root, fs-radio-group, fs-switch-root, fs-checkbox-group',
      )!,
    ]),
  ) as Record<keyof FormValues, HTMLElement>;
  const errors = Object.fromEntries(fieldNames.map(name => [name, fields[name].querySelector('fs-field-error')])) as Record<
    keyof FormValues,
    (HTMLElement & Components.FsFieldError) | null
  >;
  const toastViewport = content.querySelector('fs-toast-viewport')!;
  container.append(content);
  return { provider, form, fields, controls, errors, toastViewport, destroy: () => provider.remove() };
}
export type FormElements = ReturnType<typeof createForm>;
```

```tsx
/* button.tsx */
import * as React from 'react';
import { Button as BaseButton } from '@base-ui/react/button';
import clsx from 'clsx';

export function Button({ className, ...props }: React.ComponentPropsWithoutRef<'button'>) {
  return (
    <BaseButton
      type="button"
      className={clsx(
        'flex h-8 items-center justify-center gap-2 rounded-none border border-neutral-950 bg-white px-3 py-0 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 disabled:border-neutral-500 disabled:text-neutral-500 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:disabled:border-neutral-400 dark:disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';

export function CheckboxGroup({ className, ...props }: BaseCheckboxGroup.Props) {
  return <BaseCheckboxGroup className={clsx('flex flex-col items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* radio-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';

export function RadioGroup<Value>({ className, ...props }: BaseRadioGroup.Props<Value>) {
  return <BaseRadioGroup className={clsx('flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* toast.tsx */
'use client';
import * as React from 'react';
import { Toast } from '@base-ui/react/toast';

function Toasts() {
  const { toasts } = Toast.useToastManager();
  return toasts.map(toast => (
    <Toast.Root
      key={toast.id}
      toast={toast}
      className="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]"
    >
      <Toast.Content className="h-full overflow-hidden p-3 transition-opacity duration-250">
        <Toast.Title className="text-sm font-bold" />
        <Toast.Description className="text-sm text-neutral-700 dark:text-neutral-300" />
        <div className="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore>
          <pre className="whitespace-pre-wrap">{JSON.stringify(toast.data, null, 2)}</pre>
        </div>
        <Toast.Close
          className="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700"
          aria-label="Close"
        >
          <XIcon />
        </Toast.Close>
      </Toast.Content>
    </Toast.Root>
  ));
}

export function ToastProvider(props: { children: React.ReactNode }) {
  return (
    <Toast.Provider limit={1}>
      {props.children}
      <Toast.Portal>
        <Toast.Viewport className="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]">
          <Toasts />
        </Toast.Viewport>
      </Toast.Portal>
    </Toast.Provider>
  );
}

export const useToastManager = Toast.useToastManager;

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m2.5 2.5 11 11m-11 0 11-11" />
    </svg>
  );
}
```

```tsx
/* autocomplete.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Autocomplete } from '@base-ui/react/autocomplete';

export function Root(props: Autocomplete.Root.Props<any>) {
  return <Autocomplete.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Autocomplete.Input.Props>(function Input(
  { className, ...props }: Autocomplete.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Autocomplete.Input
      ref={forwardedRef}
      className={clsx(
        'h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Portal(props: Autocomplete.Portal.Props) {
  return <Autocomplete.Portal {...props} />;
}

export function Positioner({ className, ...props }: Autocomplete.Positioner.Props) {
  return <Autocomplete.Positioner className={clsx('outline-none data-empty:hidden', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Autocomplete.Popup.Props) {
  return (
    <Autocomplete.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Autocomplete.List.Props) {
  return (
    <Autocomplete.List
      className={clsx('max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Autocomplete.Item.Props) {
  return (
    <Autocomplete.Item
      className={clsx(
        'flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Checkbox } from '@base-ui/react/checkbox';

export function Root({ className, ...props }: Checkbox.Root.Props) {
  return (
    <Checkbox.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Checkbox.Indicator.Props) {
  return <Checkbox.Indicator className={clsx('flex data-unchecked:hidden', className)} {...props} />;
}
```

```tsx
/* combobox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Combobox } from '@base-ui/react/combobox';

export function Root(props: Combobox.Root.Props<any, any>) {
  return <Combobox.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Combobox.Input.Props>(function Input(
  { className, ...props }: Combobox.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Combobox.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function InputGroup({ className, ...props }: Combobox.InputGroup.Props) {
  return (
    <Combobox.InputGroup
      className={clsx(
        'relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>input]:pr-[2.5rem] has-[.combobox-clear]:[&>input]:pr-[calc(0.5rem+2rem*2)]',
        className,
      )}
      {...props}
    />
  );
}

export function Clear({ className, ...props }: Combobox.Clear.Props) {
  return (
    <Combobox.Clear
      className={clsx('combobox-clear flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)}
      {...props}
    >
      <XIcon />
    </Combobox.Clear>
  );
}

export function Trigger({ className, ...props }: Combobox.Trigger.Props) {
  return <Combobox.Trigger className={clsx('flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Portal(props: Combobox.Portal.Props) {
  return <Combobox.Portal {...props} />;
}

export function Positioner({ className, ...props }: Combobox.Positioner.Props) {
  return <Combobox.Positioner className={clsx('outline-none', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Combobox.Popup.Props) {
  return (
    <Combobox.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function Empty({ className, children, ...props }: Combobox.Empty.Props) {
  return (
    <Combobox.Empty {...props}>
      {children ? <div className={clsx('py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400', className)}>{children}</div> : null}
    </Combobox.Empty>
  );
}

export function List({ className, ...props }: Combobox.List.Props) {
  return (
    <Combobox.List
      className={clsx('outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Combobox.Item.Props) {
  return (
    <Combobox.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Combobox.ItemIndicator.Props) {
  return <Combobox.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function CaretDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M12 6H4l4 4.5z" />
    </svg>
  );
}

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m4.5 4.5 7 7m-7 0 7-7" />
    </svg>
  );
}
```

```tsx
/* field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Field } from '@base-ui/react/field';

export function Root({ className, ...props }: Field.Root.Props) {
  return <Field.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Label({ className, ...props }: Field.Label.Props) {
  return (
    <Field.Label
      className={clsx(
        'text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white',
        className,
      )}
      {...props}
    />
  );
}

export function Description({ className, ...props }: Field.Description.Props) {
  return <Field.Description className={clsx('text-sm text-neutral-600 dark:text-neutral-400', className)} {...props} />;
}

export const Control = React.forwardRef<HTMLInputElement, Field.Control.Props>(function FieldControl(
  { className, ...props }: Field.Control.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Field.Control
      ref={forwardedRef}
      className={clsx(
        'h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Error({ className, ...props }: Field.Error.Props) {
  return <Field.Error className={clsx('text-sm text-red-700 dark:text-red-400', className)} {...props} />;
}

export function Item(props: Field.Item.Props) {
  return <Field.Item {...props} />;
}
```

```tsx
/* fieldset.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Fieldset } from '@base-ui/react/fieldset';

export function Root(props: Fieldset.Root.Props) {
  return <Fieldset.Root {...props} />;
}

export function Legend({ className, ...props }: Fieldset.Legend.Props) {
  return <Fieldset.Legend className={clsx('text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* number-field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { NumberField } from '@base-ui/react/number-field';

export function Root({ className, ...props }: NumberField.Root.Props) {
  return <NumberField.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Group({ className, ...props }: NumberField.Group.Props) {
  return <NumberField.Group className={clsx('flex h-8', className)} {...props} />;
}

export function Decrement({ className, ...props }: NumberField.Decrement.Props) {
  return (
    <NumberField.Decrement
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}

export const Input = React.forwardRef<HTMLInputElement, NumberField.Input.Props>(function Input(
  { className, ...props }: NumberField.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <NumberField.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white',
        className,
      )}
      {...props}
    />
  );
});

export function Increment({ className, ...props }: NumberField.Increment.Props) {
  return (
    <NumberField.Increment
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* radio.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Radio } from '@base-ui/react/radio';

export function Root({ className, ...props }: Radio.Root.Props) {
  return (
    <Radio.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Radio.Indicator.Props) {
  return <Radio.Indicator className={clsx('flex items-center justify-center data-unchecked:hidden before:size-2 before:rounded-full before:bg-current', className)} {...props} />;
}
```

```tsx
/* select.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Select } from '@base-ui/react/select';

export function Root(props: Select.Root.Props<any>) {
  return <Select.Root {...props} />;
}

export function Label({ className, ...props }: Select.Label.Props) {
  return <Select.Label className={clsx('cursor-default text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Trigger({ className, ...props }: Select.Trigger.Props) {
  return (
    <Select.Trigger
      className={clsx(
        'flex h-8 min-w-40 cursor-default items-center justify-between gap-3 border border-neutral-950 bg-white pl-2 pr-1 text-sm font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 data-pressed:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:data-pressed:bg-neutral-800',
        className,
      )}
      {...props}
    />
  );
}

export function Value({ className, ...props }: Select.Value.Props) {
  return <Select.Value className={clsx('data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400', className)} {...props} />;
}

export function Icon(props: Select.Icon.Props) {
  return <Select.Icon {...props} />;
}

export function Portal(props: Select.Portal.Props) {
  return <Select.Portal {...props} />;
}

export function Positioner({ className, ...props }: Select.Positioner.Props) {
  return <Select.Positioner className={clsx('outline-none select-none z-10', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Select.Popup.Props) {
  return (
    <Select.Popup
      className={clsx(
        'group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function ScrollUpArrow({ className, ...props }: Select.ScrollUpArrow.Props) {
  return (
    <Select.ScrollUpArrow
      className={clsx(
        "top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function ScrollDownArrow({ className, ...props }: Select.ScrollDownArrow.Props) {
  return (
    <Select.ScrollDownArrow
      className={clsx(
        "bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Select.List.Props) {
  return <Select.List className={clsx('relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6', className)} {...props} />;
}

export function Item({ className, ...props }: Select.Item.Props) {
  return (
    <Select.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Select.ItemIndicator.Props) {
  return <Select.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function ItemText({ className, ...props }: Select.ItemText.Props) {
  return <Select.ItemText className={clsx('col-start-2', className)} {...props} />;
}
```

```tsx
/* slider.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Slider } from '@base-ui/react/slider';

export function Root({ className, ...props }: Slider.Root.Props<any>) {
  return <Slider.Root className={clsx('grid grid-cols-2', className)} {...props} />;
}

export function Value({ className, ...props }: Slider.Value.Props) {
  return <Slider.Value className={clsx('text-sm font-normal text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Control({ className, ...props }: Slider.Control.Props) {
  return <Slider.Control className={clsx('flex col-span-2 touch-none items-center py-3 select-none', className)} {...props} />;
}

export function Track({ className, ...props }: Slider.Track.Props) {
  return <Slider.Track className={clsx('h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800', className)} {...props} />;
}

export function Indicator({ className, ...props }: Slider.Indicator.Props) {
  return <Slider.Indicator className={clsx('bg-neutral-950 select-none dark:bg-white', className)} {...props} />;
}

export function Thumb({ className, ...props }: Slider.Thumb.Props) {
  return (
    <Slider.Thumb
      className={clsx(
        'size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* switch.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Switch } from '@base-ui/react/switch';

export function Root({ className, ...props }: Switch.Root.Props) {
  return (
    <Switch.Root
      className={clsx(
        'flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function Thumb({ className, ...props }: Switch.Thumb.Props) {
  return (
    <Switch.Thumb
      className={clsx(
        'size-3.5 bg-neutral-950 transition-[translate,background-color] duration-150 ease-[ease] data-checked:translate-x-4 data-checked:bg-white dark:bg-white dark:data-checked:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```ts
/* stencil-themed-tanstack-form.ts */
import { mount as mountForm } from './stencil-tanstack-form';
import './stencil-form.css';

export function mount(container: HTMLElement) {
  return mountForm(container, true);
}
```

```ts
/* stencil-tanstack-form.ts */
import { FormApi, FieldApi, revalidateLogic, type DeepKeys, type ValidationError } from '@tanstack/form-core';
import { createForm, defaultValues, fieldNames, type FormValues } from './stencil-form';
import { connectField } from './stencil-form-events';
import { connectToasts } from './stencil-toast';

export function mount(container: HTMLElement, themed = false) {
  const elements = createForm(container, { externalValidation: true, nativeForm: true, themed });
  const toasts = connectToasts(elements.provider, elements.toastViewport, themed);
  const form = new FormApi({
    defaultValues,
    onSubmit: ({ value }) => {
      toasts.submit(value);
    },
    validationLogic: revalidateLogic({ mode: 'submit', modeAfterSubmission: 'change' }),
    validators: {
      onDynamic: ({ value }) => {
        const errors: Partial<Record<DeepKeys<FormValues>, ValidationError>> = {};
        (['serverName', 'region', 'containerImage', 'serverType', 'numOfInstances'] as const).forEach(name => {
          if (!value[name]) errors[name] = 'This is a required field.';
        });
        if (value.serverName && value.serverName.length < 3) errors.serverName = 'At least 3 characters.';
        return Object.keys(errors).length ? { form: errors, fields: errors } : undefined;
      },
    },
  });
  const unmountForm = form.mount();
  const cleanupFields = fieldNames.map(name => {
    const field = new FieldApi({ form, name });
    const unmountField = field.mount();
    const connection = connectField(elements, name, field.handleChange, field.handleBlur);
    const update = () =>
      connection.update({
        value: field.state.value,
        invalid: !field.state.meta.isValid,
        dirty: field.state.meta.isDirty,
        touched: field.state.meta.isTouched,
        error: field.state.meta.errors.join(','),
      });
    const subscription = field.store.subscribe(update);
    update();
    return () => {
      subscription.unsubscribe();
      connection.destroy();
      unmountField();
    };
  });
  const submit = (event: Event) => {
    event.preventDefault();
    void form.handleSubmit();
  };
  elements.form.addEventListener('submit', submit);
  return () => {
    elements.form.removeEventListener('submit', submit);
    cleanupFields.forEach(cleanup => cleanup());
    unmountForm();
    toasts.destroy();
    elements.destroy();
  };
}
```

```css
/* stencil-form.css */
/* Shared layout for the three theme-based Handbook forms. */
@layer fs-theme {
  .handbook-form {
    --fs-form-gap: var(--fs-space-5);
    --fs-form-max-width: 16rem;
    --fs-field-max-width: none;
    --fs-combobox-input-group-width: 16rem;
    --fs-number-field-input-width: 4rem;
    --fs-number-field-input-border: 1px solid var(--fs-color-foreground);
    --fs-slider-root-width: 100%;
    --fs-slider-control-width: 100%;
    --fs-slider-label-font-weight: var(--fs-font-weight-bold);
    --fs-slider-root-row-gap: var(--fs-space-2);
    --fs-select-width: 12rem;
    --fs-select-line-height: var(--fs-line-height-sm);
  }
  /* TanStack's adapter owns a native form instead of fs-form. */
  form.handbook-form {
    display: flex;
    flex-direction: column;
    gap: var(--fs-form-gap);
    width: 100%;
    max-width: var(--fs-form-max-width);
  }
  .handbook-form-select {
    display: flex;
    flex-direction: column;
    gap: var(--fs-space-1);
    width: fit-content;
  }
  .handbook-form-group-label {
    font-size: var(--fs-font-size-sm);
    line-height: var(--fs-line-height-sm);
    font-weight: var(--fs-font-weight-bold);
    color: var(--fs-color-foreground);
  }
  :where([data-fs-variant='horizontal']) .handbook-form-group-label {
    margin-top: -1px;
  }
  .handbook-form-protocol-heading {
    margin-bottom: var(--fs-space-2);
  }
  .handbook-form-protocols {
    display: flex;
    gap: var(--fs-space-4);
  }
  .handbook-form-protocol-label {
    text-transform: uppercase;
  }
  .handbook-form-submit::part(control) {
    margin-top: var(--fs-space-3);
  }
  .handbook-form-image-url {
    font-family: 'Paper Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
    white-space: nowrap;
    font-size: 0.75rem;
    opacity: 0.8;
  }
  .handbook-form-toast-viewport {
    --fs-toast-viewport-z-index: 10;
    --fs-toast-viewport-width: 250px;
    --fs-toast-viewport-bottom: 1rem;
    --fs-toast-viewport-right: 1rem;
  }
  .handbook-form-submitted-values {
    margin-top: var(--fs-space-2);
    border: var(--fs-border-width) solid var(--fs-color-foreground);
    padding: var(--fs-space-2);
    font-size: 0.75rem;
    user-select: text;
  }
  .handbook-form-submitted-values pre {
    white-space: pre-wrap;
    font-size: 0.75rem;
    line-height: calc(1 / 0.75);
  }
  @media (min-width: 40rem) {
    .handbook-form {
      --fs-form-max-width: 20rem;
    }
    .handbook-form-toast-viewport {
      --fs-toast-viewport-width: 360px;
      --fs-toast-viewport-bottom: 2rem;
      --fs-toast-viewport-right: 2rem;
    }
  }
  @media (min-width: 48rem) {
    .handbook-form {
      --fs-autocomplete-input-width: 20rem;
    }
  }
}
```

```ts
/* stencil-form-events.ts */
import type { FormElements, FormValues } from './stencil-form';

export interface FieldState {
  value: FormValues[keyof FormValues];
  invalid: boolean;
  touched: boolean;
  dirty: boolean;
  error?: string;
}

/** The form library owns values and validation; the elements own their UI and ARIA. */
export function connectField(elements: FormElements, name: keyof FormValues, onChange: (value: any) => void, onBlur: () => void, inputRef?: (element: HTMLElement | null) => void) {
  const field = elements.fields[name];
  const control = elements.controls[name];
  const refTarget = name === 'scalingThreshold' ? field.querySelector('fs-slider-thumb')! : name === 'allowedNetworkProtocols' ? field.querySelector('fs-checkbox-root')! : control;
  const error = elements.errors[name];
  // Keep the authored text node: Field.Error can be offline while valid.
  const message = error?.querySelector('span');
  const valueProperty = name === 'restartOnFailure' ? 'checked' : 'value';
  const eventName = name === 'restartOnFailure' ? 'checkedChange' : 'valueChange';
  const change = (event: Event) => {
    if (event.target === control) onChange((event as CustomEvent).detail[valueProperty]);
  };
  control.addEventListener(eventName, change);
  if (name === 'scalingThreshold') control.addEventListener('valueCommitted', change);
  const blur = () => onBlur();
  field.addEventListener('focusout', blur);
  if (inputRef) {
    if (name === 'numOfInstances') inputRef(field.querySelector('fs-number-field-input'));
    else Reflect.set(refTarget, 'inputRef', inputRef);
  }
  return {
    update(state: FieldState) {
      Reflect.set(control, valueProperty, state.value);
      field.invalid = state.invalid;
      field.touched = state.touched;
      field.dirty = state.dirty;
      if (message) message.textContent = state.error ?? '';
      if (error) error.match = state.invalid;
    },
    destroy() {
      control.removeEventListener(eventName, change);
      control.removeEventListener('valueCommitted', change);
      field.removeEventListener('focusout', blur);
      if (inputRef) {
        Reflect.set(refTarget, 'inputRef', undefined);
        inputRef(null);
      }
    },
  };
}
```

```ts
/* stencil-toast.ts */
import { createToastManager, type ToastObject } from 'finesoft-components/toast';
import type { Components } from 'finesoft-components';

const toastHTML = `
<fs-toast-root class="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]">
  <fs-toast-content class="h-full overflow-hidden p-3 transition-opacity duration-250">
    <fs-toast-title class="text-sm font-bold"></fs-toast-title>
    <fs-toast-description class="text-sm text-neutral-700 dark:text-neutral-300"></fs-toast-description>
    <div class="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore="true">
      <pre class="whitespace-pre-wrap"></pre>
    </div>
    <fs-toast-close class="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700" aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

const themedToastHTML = `
<fs-toast-root data-fs-variant="rich">
  <fs-toast-content>
    <fs-toast-title></fs-toast-title>
    <fs-toast-description></fs-toast-description>
    <div class="handbook-form-submitted-values" data-base-ui-swipe-ignore="true">
      <pre></pre>
    </div>
    <fs-toast-close aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

export function connectToasts(provider: HTMLElement & Components.FsToastProvider, viewport: Element, themed = false) {
  const manager = createToastManager();
  const roots = new Map<string, HTMLElement & Components.FsToastRoot>();
  function update(event: CustomEvent<ToastObject[]>) {
    const toasts = event.detail;
    for (const [id, root] of roots) {
      if (!toasts.some(toast => toast.id === id)) {
        root.remove();
        roots.delete(id);
      }
    }
    for (const toast of toasts) {
      let root = roots.get(toast.id);
      if (!root) {
        const template = provider.ownerDocument.createElement('template');
        template.innerHTML = themed ? themedToastHTML : toastHTML;
        root = template.content.firstElementChild as HTMLElement & Components.FsToastRoot;
        root.toast = toast;
        root.querySelector('pre')!.textContent = JSON.stringify(toast.data, null, 2);
        roots.set(toast.id, root);
        viewport.append(root);
      } else {
        root.toast = toast;
      }
    }
  }
  provider.addEventListener('toastsChange', update as EventListener);
  provider.toastManager = manager;
  return {
    submit: (data: unknown) => manager.add({ title: 'Form submitted', description: 'The form contains these values:', data: data as Record<string, unknown> }),
    destroy: () => provider.removeEventListener('toastsChange', update as EventListener),
  };
}
```

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactExample from './react-tanstack-form';
import StencilExample from './docs-native-preview';
import { formHTML, configureForm } from './stencil-form';

export default function Comparison() {
  const options = { externalValidation: true, nativeForm: true };
  return (
    <StencilComparison
      component="handbook-form-tanstack-form"
      react={<ReactExample />}
      stencil={null}
      renderSource={() => formHTML(options)}
      beforeHydrate={document => configureForm(document, options)}
      clientStencil={<StencilExample />}
    />
  );
}
```

```tsx
/* react-tanstack-form.tsx */
'use client';
import * as React from 'react';
import { useForm, revalidateLogic, DeepKeys, ValidationError } from '@tanstack/react-form';
import { Button } from './button';
import { CheckboxGroup } from './checkbox-group';
import { RadioGroup } from './radio-group';
import { ToastProvider, useToastManager } from './toast';
import * as Autocomplete from './autocomplete';
import * as Checkbox from './checkbox';
import * as Combobox from './combobox';
import * as Field from './field';
import * as Fieldset from './fieldset';
import * as NumberField from './number-field';
import * as Radio from './radio';
import * as Select from './select';
import * as Slider from './slider';
import * as Switch from './switch';

interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};

function TanstackForm() {
  const toastManager = useToastManager();

  const form = useForm({
    defaultValues,
    onSubmit: ({ value: formValues }) => {
      toastManager.add({
        title: 'Form submitted',
        description: 'The form contains these values:',
        data: formValues,
      });
    },
    validationLogic: revalidateLogic({
      mode: 'submit',
      modeAfterSubmission: 'change',
    }),
    validators: {
      onDynamic: ({ value: formValues }) => {
        const errors: Partial<Record<DeepKeys<FormValues>, ValidationError>> = {};

        (['serverName', 'region', 'containerImage', 'serverType', 'numOfInstances'] as const).forEach(requiredField => {
          if (!formValues[requiredField]) {
            errors[requiredField] = 'This is a required field.';
          }
        });

        if (formValues.serverName && formValues.serverName.length < 3) {
          errors.serverName = 'At least 3 characters.';
        }

        return isEmpty(errors) ? undefined : { form: errors, fields: errors };
      },
    },
  });

  /* eslint-disable react/no-children-prop */
  return (
    <form
      aria-label="Launch new cloud server"
      className="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]"
      noValidate
      onSubmit={event => {
        event.preventDefault();
        form.handleSubmit();
      }}
    >
      <form.Field
        name="serverName"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Field.Label>Server name</Field.Label>
              <Field.Control value={field.state.value} onValueChange={field.handleChange} onBlur={field.handleBlur} placeholder="e.g. api-server-01" />
              <Field.Description>Must be 3 or more characters long</Field.Description>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="region"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Combobox.Root items={REGIONS} value={field.state.value} onValueChange={field.handleChange}>
                <div className="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
                  <Field.Label className="mb-1 block">Region</Field.Label>
                  <Combobox.InputGroup>
                    <Combobox.Input placeholder="e.g. eu-central-1" onBlur={field.handleBlur} />
                    <div className="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
                      <Combobox.Clear />
                      <Combobox.Trigger>
                        <Combobox.CaretDownIcon />
                      </Combobox.Trigger>
                    </div>
                  </Combobox.InputGroup>
                </div>
                <Combobox.Portal>
                  <Combobox.Positioner>
                    <Combobox.Popup>
                      <Combobox.Empty>No matches</Combobox.Empty>
                      <Combobox.List>
                        {(region: string) => {
                          return (
                            <Combobox.Item key={region} value={region}>
                              <Combobox.ItemIndicator>
                                <CheckIcon />
                              </Combobox.ItemIndicator>
                              <span className="col-start-2">{region}</span>
                            </Combobox.Item>
                          );
                        }}
                      </Combobox.List>
                    </Combobox.Popup>
                  </Combobox.Positioner>
                </Combobox.Portal>
              </Combobox.Root>

              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="containerImage"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Autocomplete.Root items={IMAGES} mode="both" value={field.state.value} onValueChange={field.handleChange} itemToStringValue={(itemValue: Image) => itemValue.url}>
                <Field.Label>Container image</Field.Label>
                <Autocomplete.Input placeholder="e.g. docker.io/library/node:latest" onBlur={field.handleBlur} />
                <Field.Description>Enter a registry URL with optional tags</Field.Description>
                <Autocomplete.Portal>
                  <Autocomplete.Positioner>
                    <Autocomplete.Popup>
                      <Autocomplete.List>
                        {(image: Image) => {
                          return (
                            <Autocomplete.Item key={image.url} value={image}>
                              <span>{image.name}</span>
                              <span className="font-mono whitespace-nowrap text-xs opacity-80">{image.url}</span>
                            </Autocomplete.Item>
                          );
                        }}
                      </Autocomplete.List>
                    </Autocomplete.Popup>
                  </Autocomplete.Positioner>
                </Autocomplete.Portal>
              </Autocomplete.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="serverType"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Select.Root items={SERVER_TYPES} value={field.state.value} onValueChange={field.handleChange}>
                <div className="w-fit space-y-1">
                  <Select.Label>Server type</Select.Label>
                  <Select.Trigger className="w-48" onBlur={field.handleBlur}>
                    <Select.Value />
                    <Select.Icon>
                      <CaretUpDownIcon />
                    </Select.Icon>
                  </Select.Trigger>
                </div>
                <Select.Portal>
                  <Select.Positioner>
                    <Select.Popup>
                      <Select.ScrollUpArrow />
                      <Select.List>
                        {SERVER_TYPES.map(({ label, value }) => {
                          return (
                            <Select.Item key={value} value={value}>
                              <Select.ItemIndicator>
                                <CheckIcon />
                              </Select.ItemIndicator>
                              <Select.ItemText>{label}</Select.ItemText>
                            </Select.Item>
                          );
                        })}
                      </Select.List>
                      <Select.ScrollDownArrow />
                    </Select.Popup>
                  </Select.Positioner>
                </Select.Portal>
              </Select.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="numOfInstances"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <NumberField.Root value={field.state.value} onValueChange={field.handleChange} min={1} max={64}>
                <Field.Label>Number of instances</Field.Label>
                <NumberField.Group>
                  <NumberField.Decrement>
                    <MinusIcon />
                  </NumberField.Decrement>
                  <NumberField.Input onBlur={field.handleBlur} />
                  <NumberField.Increment>
                    <PlusIcon />
                  </NumberField.Increment>
                </NumberField.Group>
              </NumberField.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="scalingThreshold"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Fieldset.Root
                render={
                  <Slider.Root
                    value={field.state.value}
                    onValueChange={field.handleChange}
                    onValueCommitted={field.handleChange}
                    thumbAlignment="edge"
                    min={0}
                    max={1}
                    step={0.01}
                    format={{
                      style: 'percent',
                      minimumFractionDigits: 0,
                      maximumFractionDigits: 0,
                    }}
                    className="w-full gap-y-2"
                  />
                }
              >
                <Fieldset.Legend>Scaling threshold</Fieldset.Legend>
                <Slider.Value className="col-start-2 text-end" />
                <Slider.Control>
                  <Slider.Track>
                    <Slider.Indicator />
                    <Slider.Thumb index={0} aria-label="Minimum threshold" onBlur={field.handleBlur} />
                    <Slider.Thumb index={1} aria-label="Maximum threshold" onBlur={field.handleBlur} />
                  </Slider.Track>
                </Slider.Control>
              </Fieldset.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="storageType"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Fieldset.Root render={<RadioGroup value={field.state.value} onValueChange={field.handleChange} className="gap-4" />}>
                <Fieldset.Legend className="-mt-px">Storage type</Fieldset.Legend>
                {['ssd', 'hdd'].map(radioValue => (
                  <Field.Item key={radioValue}>
                    <Field.Label className="uppercase">
                      <Radio.Root value={radioValue}>
                        <Radio.Indicator />
                      </Radio.Root>
                      {radioValue}
                    </Field.Label>
                  </Field.Item>
                ))}
              </Fieldset.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="restartOnFailure"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Field.Label className="gap-2">
                Restart on failure
                <Switch.Root checked={field.state.value} onCheckedChange={field.handleChange} onBlur={field.handleBlur}>
                  <Switch.Thumb />
                </Switch.Root>
              </Field.Label>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <form.Field
        name="allowedNetworkProtocols"
        children={field => {
          return (
            <Field.Root name={field.name} invalid={!field.state.meta.isValid} dirty={field.state.meta.isDirty} touched={field.state.meta.isTouched}>
              <Fieldset.Root render={<CheckboxGroup value={field.state.value} onValueChange={field.handleChange} />}>
                <Fieldset.Legend className="mb-2">Allowed network protocols</Fieldset.Legend>
                <div className="flex gap-4">
                  {['http', 'https', 'ssh'].map(checkboxValue => {
                    return (
                      <Field.Item key={checkboxValue}>
                        <Field.Label className="uppercase">
                          <Checkbox.Root value={checkboxValue} onBlur={field.handleBlur}>
                            <Checkbox.Indicator>
                              <CheckIcon />
                            </Checkbox.Indicator>
                          </Checkbox.Root>
                          {checkboxValue}
                        </Field.Label>
                      </Field.Item>
                    );
                  })}
                </div>
              </Fieldset.Root>
              <Field.Error match={!field.state.meta.isValid}>{field.state.meta.errors.join(',')}</Field.Error>
            </Field.Root>
          );
        }}
      />

      <Button type="submit" className="mt-3">
        Launch server
      </Button>
    </form>
  );
}

export default function App() {
  return (
    <ToastProvider>
      <TanstackForm />
    </ToastProvider>
  );
}

function CaretUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="m2.5 8.5 4 4 7-9" />
    </svg>
  );
}

function PlusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13M8 14.5v-13" />
    </svg>
  );
}

function MinusIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="M1.5 8h13" />
    </svg>
  );
}

function isEmpty(object: Partial<Record<DeepKeys<FormValues>, ValidationError>>) {
  // eslint-disable-next-line
  for (const _ in object) {
    return false;
  }
  return true;
}

function cartesian<T extends string[][]>(...arrays: T): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}

const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));

interface Image {
  url: string;
  name: string;
}
/* prettier-ignore */
const IMAGES: Image[] = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map((name) => ({
  url: `docker.io/library/${name}`,
  name,
}));

const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];
```

```tsx
/* docs-native-preview.tsx */
'use client';
import { NativeStencilPreview } from 'docs/src/components/NativeStencilPreview';
import { mount } from './stencil-tanstack-form';
export default function Preview() {
  return <NativeStencilPreview mount={mount} />;
}
```

```ts
/* stencil-form.ts */
import type { Components } from 'finesoft-components';

export interface FormValues {
  serverName: string;
  region: string | null;
  containerImage: string;
  serverType: string | null;
  numOfInstances: number | null;
  scalingThreshold: number[];
  storageType: 'ssd' | 'hdd';
  restartOnFailure: boolean;
  allowedNetworkProtocols: string[];
}

export const defaultValues: FormValues = {
  serverName: '',
  region: null,
  containerImage: '',
  serverType: null,
  numOfInstances: null,
  scalingThreshold: [0.2, 0.8],
  storageType: 'ssd',
  restartOnFailure: true,
  allowedNetworkProtocols: [],
};
export const fieldNames = Object.keys(defaultValues) as Array<keyof FormValues>;
export interface FormOptions {
  externalValidation?: boolean;
  nativeForm?: boolean;
  themed?: boolean;
}

function cartesian(...arrays: string[][]): string[][] {
  return arrays.reduce<string[][]>((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}
const REGIONS = cartesian(['us', 'eu', 'ap'], ['central', 'east', 'west'], ['1', '2', '3']).map(part => part.join('-'));
const IMAGES = ['nginx:1.29-alpine', 'node:22-slim', 'postgres:18', 'redis:8.2.2-alpine'].map(name => ({ name, url: `docker.io/library/${name}` }));
const SERVER_TYPES = [
  { label: 'Select server type', value: null },
  ...cartesian(['t', 'm'], ['1', '2'], ['small', 'medium', 'large']).map(part => {
    const value = part.join('.').replace('.', '');
    return { label: value, value };
  }),
];

// This same Web Components declaration is used by the browser and by Stencil SSR.
// The framework integrations below only exchange public properties and events.
export function formHTML(options: FormOptions = {}): string {
  if (options.themed) return themedFormHTML(options);
  const { nativeForm = false } = options;
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="flex w-full max-w-3xs flex-col gap-5 sm:max-w-[20rem]" aria-label="Launch new cloud server">
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverName">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Server name</fs-field-label>
      <fs-field-control class="h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Must be 3 or more characters long</fs-field-description>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="region">
      <fs-combobox-root required="">
        <div class="relative text-sm leading-5 font-bold text-neutral-950 dark:text-white">
          <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white mb-1 block'>Region</fs-field-label>
          <fs-combobox-input-group class="relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>fs-combobox-input>input]:pr-[2.5rem] has-[.combobox-clear]:[&>fs-combobox-input>input]:pr-[calc(0.5rem+2rem*2)]">
            <fs-combobox-input class="h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div class="absolute right-0 bottom-0 inline-flex h-full items-center justify-center text-neutral-500 dark:text-neutral-400">
              <fs-combobox-clear class="[&::part(clear)]:box-border [&::part(clear)]:m-0 [&::part(clear)]:p-0 [&::part(clear)]:border-solid [&::part(clear)]:[font-family:inherit] [&::part(clear)]:[font-size:inherit] [&::part(clear)]:[font-weight:inherit] [&::part(clear)]:[line-height:inherit] combobox-clear [&::part(clear)]:flex [&::part(clear)]:h-full [&::part(clear)]:w-6 [&::part(clear)]:items-center [&::part(clear)]:justify-center [&::part(clear)]:border-0 [&::part(clear)]:bg-transparent [&::part(clear)]:p-0 [&::part(clear)]:text-neutral-950 dark:[&::part(clear)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:p-0 [&::part(trigger)]:border-solid [&::part(trigger)]:[font-family:inherit] [&::part(trigger)]:[font-size:inherit] [&::part(trigger)]:[font-weight:inherit] [&::part(trigger)]:[line-height:inherit] [&::part(trigger)]:flex [&::part(trigger)]:h-full [&::part(trigger)]:w-6 [&::part(trigger)]:items-center [&::part(trigger)]:justify-center [&::part(trigger)]:border-0 [&::part(trigger)]:bg-transparent [&::part(trigger)]:p-0 [&::part(trigger)]:text-neutral-950 dark:[&::part(trigger)]:text-white">
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner class="outline-none" side-offset="4">
            <fs-combobox-popup class="w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-combobox-empty>
                <div class="py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400">No matches</div>
              </fs-combobox-empty>
              <fs-combobox-list class="outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0">${REGIONS.map(
                region => `
<fs-combobox-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white" value="${region}">
  <fs-combobox-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span class="col-start-2">${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Container image</fs-field-label>
        <fs-autocomplete-input class="h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400" placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description class="[&::part(description)]:m-0 text-sm text-neutral-600 dark:text-neutral-400">Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner class="outline-none data-empty:hidden" side-offset="4">
            <fs-autocomplete-popup class="w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-autocomplete-list class="max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0">${IMAGES.map(
                image => `
<fs-autocomplete-item class="flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white">
  <span>${image.name}</span>
  <span class="font-mono whitespace-nowrap text-xs opacity-80">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="serverType">
      <fs-select-root required="">
        <div class="w-fit space-y-1">
          <fs-select-label class="cursor-default text-sm font-bold text-neutral-950 dark:text-white">Server type</fs-select-label>
          <fs-select-trigger class="[&::part(trigger)]:box-border [&::part(trigger)]:m-0 [&::part(trigger)]:font-[inherit] [&::part(trigger)]:border-solid [&::part(trigger)]:p-0 [&::part(trigger)]:flex [&::part(trigger)]:h-8 [&::part(trigger)]:min-w-40 [&::part(trigger)]:cursor-default [&::part(trigger)]:items-center [&::part(trigger)]:justify-between [&::part(trigger)]:gap-3 [&::part(trigger)]:border [&::part(trigger)]:border-neutral-950 [&::part(trigger)]:bg-white [&::part(trigger)]:pl-2 [&::part(trigger)]:pr-1 [&::part(trigger)]:text-sm [&::part(trigger)]:font-normal [&::part(trigger)]:text-neutral-950 [&::part(trigger)]:select-none not-data-disabled:[&::part(trigger)]:hover:bg-neutral-100 not-data-disabled:[&::part(trigger)]:active:bg-neutral-200 data-disabled:[&::part(trigger)]:border-neutral-500 data-disabled:[&::part(trigger)]:text-neutral-500 data-pressed:[&::part(trigger)]:bg-neutral-100 [&::part(trigger):focus-visible]:outline-2 [&::part(trigger):focus-visible]:-outline-offset-1 [&::part(trigger):focus-visible]:outline-neutral-950 dark:[&::part(trigger):focus-visible]:outline-white dark:[&::part(trigger)]:border-white dark:[&::part(trigger)]:bg-neutral-950 dark:[&::part(trigger)]:text-white dark:not-data-disabled:[&::part(trigger)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(trigger)]:active:bg-neutral-700 dark:data-disabled:[&::part(trigger)]:border-neutral-400 dark:data-disabled:[&::part(trigger)]:text-neutral-400 dark:data-pressed:[&::part(trigger)]:bg-neutral-800 [&::part(trigger)]:w-48">
            <fs-select-value class="data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400"></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner class="outline-none select-none z-10" side-offset="4">
            <fs-select-popup class="group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none">
              <fs-select-scroll-up-arrow class="top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950"></fs-select-scroll-up-arrow>
              <fs-select-list class="relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6">${SERVER_TYPES.map(
                item => `
<fs-select-item class="grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950">
  <fs-select-item-indicator class="col-start-1">
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text class="col-start-2">${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow class="bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950"></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="numOfInstances">
      <fs-number-field-root class="flex flex-col items-start gap-1" min="1" max="64" required="">
        <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white'>Number of instances</fs-field-label>
        <fs-number-field-group class="[&::part(group)]:flex [&::part(group)]:h-8">
          <fs-number-field-decrement class="[&::part(decrement)]:box-border [&::part(decrement)]:m-0 [&::part(decrement)]:p-0 [&::part(decrement)]:border-solid [&::part(decrement)]:[font-family:inherit] [&::part(decrement)]:[font-size:inherit] [&::part(decrement)]:[font-weight:inherit] [&::part(decrement)]:[line-height:inherit] [&::part(decrement)]:flex [&::part(decrement)]:h-full [&::part(decrement)]:w-8 [&::part(decrement)]:items-center [&::part(decrement)]:justify-center [&::part(decrement)]:rounded-none [&::part(decrement)]:border [&::part(decrement)]:border-neutral-950 [&::part(decrement)]:bg-white [&::part(decrement)]:bg-clip-padding [&::part(decrement)]:text-neutral-950 [&::part(decrement)]:outline-0 [&::part(decrement)]:select-none not-data-disabled:[&::part(decrement)]:hover:bg-neutral-100 not-data-disabled:[&::part(decrement)]:active:bg-neutral-200 data-disabled:[&::part(decrement)]:border-neutral-500 data-disabled:[&::part(decrement)]:text-neutral-500 [&::part(decrement):focus-visible]:z-1 [&::part(decrement):focus-visible]:outline-2 [&::part(decrement):focus-visible]:-outline-offset-1 [&::part(decrement):focus-visible]:outline-neutral-950 dark:[&::part(decrement):focus-visible]:outline-white dark:[&::part(decrement)]:border-white dark:[&::part(decrement)]:bg-neutral-950 dark:[&::part(decrement)]:text-white dark:not-data-disabled:[&::part(decrement)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(decrement)]:active:bg-neutral-700 dark:data-disabled:[&::part(decrement)]:border-neutral-400 dark:data-disabled:[&::part(decrement)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input class="h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white"></fs-number-field-input>
          <fs-number-field-increment class="[&::part(increment)]:box-border [&::part(increment)]:m-0 [&::part(increment)]:p-0 [&::part(increment)]:border-solid [&::part(increment)]:[font-family:inherit] [&::part(increment)]:[font-size:inherit] [&::part(increment)]:[font-weight:inherit] [&::part(increment)]:[line-height:inherit] [&::part(increment)]:flex [&::part(increment)]:h-full [&::part(increment)]:w-8 [&::part(increment)]:items-center [&::part(increment)]:justify-center [&::part(increment)]:rounded-none [&::part(increment)]:border [&::part(increment)]:border-neutral-950 [&::part(increment)]:bg-white [&::part(increment)]:bg-clip-padding [&::part(increment)]:text-neutral-950 [&::part(increment)]:outline-0 [&::part(increment)]:select-none not-data-disabled:[&::part(increment)]:hover:bg-neutral-100 not-data-disabled:[&::part(increment)]:active:bg-neutral-200 data-disabled:[&::part(increment)]:border-neutral-500 data-disabled:[&::part(increment)]:text-neutral-500 [&::part(increment):focus-visible]:z-1 [&::part(increment):focus-visible]:outline-2 [&::part(increment):focus-visible]:-outline-offset-1 [&::part(increment):focus-visible]:outline-neutral-950 dark:[&::part(increment):focus-visible]:outline-white dark:[&::part(increment)]:border-white dark:[&::part(increment)]:bg-neutral-950 dark:[&::part(increment)]:text-white dark:not-data-disabled:[&::part(increment)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(increment)]:active:bg-neutral-700 dark:data-disabled:[&::part(increment)]:border-neutral-400 dark:data-disabled:[&::part(increment)]:text-neutral-400">
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error class="text-sm text-red-700 dark:text-red-400"></fs-field-error>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="scalingThreshold">
        <fs-slider-root class="grid grid-cols-2 w-full gap-y-2" thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label class="text-sm font-bold text-neutral-950 dark:text-white">Scaling threshold</fs-slider-label>
          <fs-slider-value class="text-sm font-normal text-neutral-950 dark:text-white col-start-2 text-end"></fs-slider-value>
          <fs-slider-control class="flex col-span-2 touch-none items-center py-3 select-none">
            <fs-slider-track class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
              <fs-slider-indicator class="bg-neutral-950 select-none dark:bg-white"></fs-slider-indicator>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb class="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950" index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="storageType">
        <fs-radio-group aria-label="Storage type" class="flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white gap-4" default-value="ssd">
          <div class="text-sm font-bold text-neutral-950 dark:text-white -mt-px">Storage type</div>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'ssd' : 'SSD'}
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white${nativeForm ? ' uppercase' : ''}'>
              <fs-radio-root class="flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="hdd">
                <fs-radio-indicator class="[&::part(indicator)]:flex [&::part(indicator)]:items-center [&::part(indicator)]:justify-center data-unchecked:[&::part(indicator)]:hidden [&::part(indicator)]:before:size-2 [&::part(indicator)]:before:rounded-full [&::part(indicator)]:before:bg-current"></fs-radio-indicator>
              </fs-radio-root>
              ${nativeForm ? 'hdd' : 'HDD'}
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="restartOnFailure">
      <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white gap-2'>
        Restart on failure
        <fs-switch-root class="flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white" default-checked="">
          <fs-switch-thumb class="[&::part(thumb)]:size-3.5 [&::part(thumb)]:bg-neutral-950 [&::part(thumb)]:transition-[translate,background-color] [&::part(thumb)]:duration-150 [&::part(thumb)]:ease-[ease] data-checked:[&::part(thumb)]:translate-x-4 data-checked:[&::part(thumb)]:bg-white dark:[&::part(thumb)]:bg-white dark:data-checked:[&::part(thumb)]:bg-neutral-950"></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root class="[&::part(field)]:flex [&::part(field)]:flex-col [&::part(field)]:items-start [&::part(field)]:gap-1" name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols" class="flex flex-col items-start gap-1 text-neutral-950 dark:text-white">
          <div class="text-sm font-bold text-neutral-950 dark:text-white mb-2">Allowed network protocols</div>
          <div class="flex gap-4">
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="http">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="https">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class='text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white uppercase'>
                <fs-checkbox-root class="flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950" value="ssh">
                  <fs-checkbox-indicator class="[&::part(indicator)]:box-border [&::part(indicator)]:flex [&[data-unchecked]::part(indicator)]:hidden">
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button type="submit" class="[&::part(control)]:p-0 [&::part(control)]:flex [&::part(control)]:h-8 [&::part(control)]:items-center [&::part(control)]:justify-center [&::part(control)]:gap-2 [&::part(control)]:rounded-none [&::part(control)]:border [&::part(control)]:border-neutral-950 [&::part(control)]:bg-white [&::part(control)]:px-3 [&::part(control)]:py-0 [&::part(control)]:[font-family:inherit] [&::part(control)]:text-sm [&::part(control)]:leading-none [&::part(control)]:whitespace-nowrap [&::part(control)]:font-normal [&::part(control)]:text-neutral-950 [&::part(control)]:select-none not-data-disabled:[&::part(control)]:hover:bg-neutral-100 not-data-disabled:[&::part(control)]:active:bg-neutral-200 data-disabled:[&::part(control)]:border-neutral-500 data-disabled:[&::part(control)]:text-neutral-500 disabled:[&::part(control)]:border-neutral-500 disabled:[&::part(control)]:text-neutral-500 [&::part(control):focus-visible]:outline-2 [&::part(control):focus-visible]:-outline-offset-1 [&::part(control):focus-visible]:outline-neutral-950 dark:[&::part(control):focus-visible]:outline-white dark:[&::part(control)]:border-white dark:[&::part(control)]:bg-neutral-950 dark:[&::part(control)]:text-white dark:not-data-disabled:[&::part(control)]:hover:bg-neutral-800 dark:not-data-disabled:[&::part(control)]:active:bg-neutral-700 dark:data-disabled:[&::part(control)]:border-neutral-400 dark:data-disabled:[&::part(control)]:text-neutral-400 dark:disabled:[&::part(control)]:border-neutral-400 dark:disabled:[&::part(control)]:text-neutral-400 [&::part(control)]:mt-3">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

function themedFormHTML({ nativeForm = false }: FormOptions = {}): string {
  const html = `
<fs-toast-provider limit="1">
  <fs-form class="handbook-form" aria-label="Launch new cloud server">
    <fs-field-root name="serverName">
      <fs-field-label>Server name</fs-field-label>
      <fs-field-control default-value="" placeholder="e.g. api-server-01" required="" minlength="3" pattern=".*[A-Za-z].*"></fs-field-control>
      <fs-field-description>Must be 3 or more characters long</fs-field-description>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="region">
      <fs-combobox-root required="">
        <div>
          <fs-field-label>Region</fs-field-label>
          <fs-combobox-input-group>
            <fs-combobox-input placeholder="e.g. eu-central-1"></fs-combobox-input>
            <div>
              <fs-combobox-clear>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
                  <path d="m4.5 4.5 7 7m-7 0 7-7"></path>
                </svg>
              </fs-combobox-clear>
              <fs-combobox-trigger>
                <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                  <path d="M12 6H4l4 4.5z"></path>
                </svg>
              </fs-combobox-trigger>
            </div>
          </fs-combobox-input-group>
        </div>
        <fs-combobox-portal>
          <fs-combobox-positioner side-offset="4">
            <fs-combobox-popup>
              <fs-combobox-empty><div>No matches</div></fs-combobox-empty>
              <fs-combobox-list>${REGIONS.map(
                region => `
<fs-combobox-item value="${region}">
  <fs-combobox-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-combobox-item-indicator>
  <span>${region}</span>
</fs-combobox-item>
`,
              ).join('')}</fs-combobox-list>
            </fs-combobox-popup>
          </fs-combobox-positioner>
        </fs-combobox-portal>
      </fs-combobox-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="containerImage">
      <fs-autocomplete-root mode="both" required="">
        <fs-field-label>Container image</fs-field-label>
        <fs-autocomplete-input placeholder="e.g. docker.io/library/node:latest"></fs-autocomplete-input>
        <fs-field-description>Enter a registry URL with optional tags</fs-field-description>
        <fs-autocomplete-portal>
          <fs-autocomplete-positioner data-fs-variant="hide-empty" side-offset="4">
            <fs-autocomplete-popup>
              <fs-autocomplete-list>${IMAGES.map(
                image => `
<fs-autocomplete-item data-fs-variant="stacked">
  <span>${image.name}</span>
  <span class="handbook-form-image-url">${image.url}</span>
</fs-autocomplete-item>
`,
              ).join('')}</fs-autocomplete-list>
            </fs-autocomplete-popup>
          </fs-autocomplete-positioner>
        </fs-autocomplete-portal>
      </fs-autocomplete-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="serverType">
      <fs-select-root required="">
        <div class="handbook-form-select">
          <fs-select-label>Server type</fs-select-label>
          <fs-select-trigger>
            <fs-select-value></fs-select-value>
            <fs-select-icon>
              <svg width="16" height="16" viewbox="0 0 16 16" fill="currentColor" style="display:block">
                <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z"></path>
              </svg>
            </fs-select-icon>
          </fs-select-trigger>
        </div>
        <fs-select-portal>
          <fs-select-positioner side-offset="4">
            <fs-select-popup>
              <fs-select-scroll-up-arrow></fs-select-scroll-up-arrow>
              <fs-select-list>${SERVER_TYPES.map(
                item => `
<fs-select-item>
  <fs-select-item-indicator>
    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
      <path d="m2.5 8.5 4 4 7-9"></path>
    </svg>
  </fs-select-item-indicator>
  <fs-select-item-text>${item.label}</fs-select-item-text>
</fs-select-item>
`,
              ).join('')}</fs-select-list>
              <fs-select-scroll-down-arrow></fs-select-scroll-down-arrow>
            </fs-select-popup>
          </fs-select-positioner>
        </fs-select-portal>
      </fs-select-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="numOfInstances">
      <fs-number-field-root min="1" max="64" required="">
        <fs-field-label>Number of instances</fs-field-label>
        <fs-number-field-group data-fs-variant="segmented">
          <fs-number-field-decrement>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13"></path>
            </svg>
          </fs-number-field-decrement>
          <fs-number-field-input></fs-number-field-input>
          <fs-number-field-increment>
            <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
              <path d="M1.5 8h13M8 14.5v-13"></path>
            </svg>
          </fs-number-field-increment>
        </fs-number-field-group>
      </fs-number-field-root>
      <fs-field-error></fs-field-error>
    </fs-field-root>
    <fs-field-root name="scalingThreshold">
        <fs-slider-root thumb-alignment="edge" min="0" max="1" step="0.01">
          <fs-slider-label>Scaling threshold</fs-slider-label>
          <fs-slider-value></fs-slider-value>
          <fs-slider-control>
            <fs-slider-track>
              <fs-slider-indicator></fs-slider-indicator>
              <fs-slider-thumb index="0" aria-label="Minimum threshold"></fs-slider-thumb>
              <fs-slider-thumb index="1" aria-label="Maximum threshold"></fs-slider-thumb>
            </fs-slider-track>
          </fs-slider-control>
        </fs-slider-root>
    </fs-field-root>
    <fs-field-root name="storageType">
        <fs-radio-group data-fs-variant="horizontal" aria-label="Storage type" default-value="ssd">
          <div class="handbook-form-group-label">Storage type</div>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="ssd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              SSD
            </fs-field-label>
          </fs-field-item>
          <fs-field-item>
            <fs-field-label>
              <fs-radio-root value="hdd">
                <fs-radio-indicator></fs-radio-indicator>
              </fs-radio-root>
              HDD
            </fs-field-label>
          </fs-field-item>
        </fs-radio-group>
    </fs-field-root>
    <fs-field-root name="restartOnFailure">
      <fs-field-label>
        Restart on failure
        <fs-switch-root default-checked="">
          <fs-switch-thumb></fs-switch-thumb>
        </fs-switch-root>
      </fs-field-label>
    </fs-field-root>
    <fs-field-root name="allowedNetworkProtocols">
        <fs-checkbox-group aria-label="Allowed network protocols">
          <div class="handbook-form-group-label handbook-form-protocol-heading">Allowed network protocols</div>
          <div class="handbook-form-protocols">
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="http">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                http
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="https">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                https
              </fs-field-label>
            </fs-field-item>
            <fs-field-item>
              <fs-field-label class="handbook-form-protocol-label">
                <fs-checkbox-root value="ssh">
                  <fs-checkbox-indicator>
                    <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" style="display:block">
                      <path d="m2.5 8.5 4 4 7-9"></path>
                    </svg>
                  </fs-checkbox-indicator>
                </fs-checkbox-root>
                ssh
              </fs-field-label>
            </fs-field-item>
          </div>
        </fs-checkbox-group>
    </fs-field-root>
    <fs-button class="handbook-form-submit" type="submit">Launch server</fs-button>
  </fs-form>
  <fs-toast-portal>
    <fs-toast-viewport class="handbook-form-toast-viewport"></fs-toast-viewport>
  </fs-toast-portal>
</fs-toast-provider>
`;
  return nativeForm ? html.replaceAll('fs-form', 'form') : html;
}

export function configureForm(scope: ParentNode, { externalValidation = false }: FormOptions = {}) {
  const combobox = scope.querySelector('fs-combobox-root') as HTMLElement & Components.FsComboboxRoot;
  combobox.items = REGIONS;
  const autocomplete = scope.querySelector('fs-autocomplete-root') as HTMLElement & Components.FsAutocompleteRoot;
  autocomplete.items = IMAGES;
  autocomplete.itemToStringValue = (item: (typeof IMAGES)[number]) => item.url;
  scope.querySelectorAll('fs-autocomplete-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsAutocompleteItem).value = IMAGES[index];
  });
  (scope.querySelector('fs-select-root') as HTMLElement & Components.FsSelectRoot).items = SERVER_TYPES;
  scope.querySelectorAll('fs-select-item').forEach((item, index) => {
    (item as HTMLElement & Components.FsSelectItem).value = SERVER_TYPES[index].value;
  });
  Object.assign(scope.querySelector('fs-slider-root')!, {
    defaultValue: [0.2, 0.8],
    format: { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0 },
  });
  (scope.querySelector('fs-checkbox-group') as HTMLElement & Components.FsCheckboxGroup).defaultValue = [];
  if (externalValidation) {
    scope.querySelectorAll('[required], [minlength], [pattern]').forEach(element => {
      for (const name of ['required', 'minlength', 'pattern']) element.removeAttribute(name);
    });
    scope.querySelectorAll('fs-field-root').forEach(element => Object.assign(element, { invalid: false, touched: false, dirty: false }));
    scope.querySelectorAll('fs-field-error').forEach(element => {
      (element as HTMLElement & Components.FsFieldError).match = false;
      element.append(element.ownerDocument.createElement('span'));
    });
  }
  scope.querySelector('form')?.setAttribute('novalidate', '');
}

export function createForm(container: HTMLElement, options: FormOptions = {}) {
  const template = container.ownerDocument.createElement('template');
  template.innerHTML = formHTML(options);
  const content = template.content;
  // Arrays, item objects and callbacks are properties, not JSON attributes.
  // Set them before connecting the elements, including the initially offline Portal parts.
  configureForm(content, options);
  const provider = content.querySelector('fs-toast-provider') as HTMLElement & Components.FsToastProvider;
  const form = content.querySelector('fs-form, form') as HTMLElement & Components.FsForm;
  const fields = Object.fromEntries(fieldNames.map(name => [name, content.querySelector(`fs-field-root[name="${name}"]`)!])) as Record<
    keyof FormValues,
    HTMLElement & Components.FsFieldRoot
  >;
  const controls = Object.fromEntries(
    fieldNames.map(name => [
      name,
      fields[name].querySelector(
        'fs-field-control, fs-combobox-root, fs-autocomplete-root, fs-select-root, fs-number-field-root, fs-slider-root, fs-radio-group, fs-switch-root, fs-checkbox-group',
      )!,
    ]),
  ) as Record<keyof FormValues, HTMLElement>;
  const errors = Object.fromEntries(fieldNames.map(name => [name, fields[name].querySelector('fs-field-error')])) as Record<
    keyof FormValues,
    (HTMLElement & Components.FsFieldError) | null
  >;
  const toastViewport = content.querySelector('fs-toast-viewport')!;
  container.append(content);
  return { provider, form, fields, controls, errors, toastViewport, destroy: () => provider.remove() };
}
export type FormElements = ReturnType<typeof createForm>;
```

```tsx
/* button.tsx */
import * as React from 'react';
import { Button as BaseButton } from '@base-ui/react/button';
import clsx from 'clsx';

export function Button({ className, ...props }: React.ComponentPropsWithoutRef<'button'>) {
  return (
    <BaseButton
      type="button"
      className={clsx(
        'flex h-8 items-center justify-center gap-2 rounded-none border border-neutral-950 bg-white px-3 py-0 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 disabled:border-neutral-500 disabled:text-neutral-500 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:disabled:border-neutral-400 dark:disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';

export function CheckboxGroup({ className, ...props }: BaseCheckboxGroup.Props) {
  return <BaseCheckboxGroup className={clsx('flex flex-col items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* radio-group.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';

export function RadioGroup<Value>({ className, ...props }: BaseRadioGroup.Props<Value>) {
  return <BaseRadioGroup className={clsx('flex w-full flex-row items-start gap-1 text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* toast.tsx */
'use client';
import * as React from 'react';
import { Toast } from '@base-ui/react/toast';

function Toasts() {
  const { toasts } = Toast.useToastManager();
  return toasts.map(toast => (
    <Toast.Root
      key={toast.id}
      toast={toast}
      className="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]"
    >
      <Toast.Content className="h-full overflow-hidden p-3 transition-opacity duration-250">
        <Toast.Title className="text-sm font-bold" />
        <Toast.Description className="text-sm text-neutral-700 dark:text-neutral-300" />
        <div className="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore>
          <pre className="whitespace-pre-wrap">{JSON.stringify(toast.data, null, 2)}</pre>
        </div>
        <Toast.Close
          className="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700"
          aria-label="Close"
        >
          <XIcon />
        </Toast.Close>
      </Toast.Content>
    </Toast.Root>
  ));
}

export function ToastProvider(props: { children: React.ReactNode }) {
  return (
    <Toast.Provider limit={1}>
      {props.children}
      <Toast.Portal>
        <Toast.Viewport className="fixed z-10 top-auto right-[1rem] bottom-[1rem] mx-auto flex w-[250px] sm:right-[2rem] sm:bottom-[2rem] sm:w-[360px]">
          <Toasts />
        </Toast.Viewport>
      </Toast.Portal>
    </Toast.Provider>
  );
}

export const useToastManager = Toast.useToastManager;

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m2.5 2.5 11 11m-11 0 11-11" />
    </svg>
  );
}
```

```tsx
/* autocomplete.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Autocomplete } from '@base-ui/react/autocomplete';

export function Root(props: Autocomplete.Root.Props<any>) {
  return <Autocomplete.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Autocomplete.Input.Props>(function Input(
  { className, ...props }: Autocomplete.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Autocomplete.Input
      ref={forwardedRef}
      className={clsx(
        'h-8 w-[16rem] border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white md:w-[20rem] dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Portal(props: Autocomplete.Portal.Props) {
  return <Autocomplete.Portal {...props} />;
}

export function Positioner({ className, ...props }: Autocomplete.Positioner.Props) {
  return <Autocomplete.Positioner className={clsx('outline-none data-empty:hidden', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Autocomplete.Popup.Props) {
  return (
    <Autocomplete.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Autocomplete.List.Props) {
  return (
    <Autocomplete.List
      className={clsx('max-h-[min(22.5rem,var(--available-height))] overflow-y-auto overscroll-contain py-1 scroll-py-1 outline-0 data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Autocomplete.Item.Props) {
  return (
    <Autocomplete.Item
      className={clsx(
        'flex cursor-default flex-col gap-0.25 py-2 pr-8 pl-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* checkbox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Checkbox } from '@base-ui/react/checkbox';

export function Root({ className, ...props }: Checkbox.Root.Props) {
  return (
    <Checkbox.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-none border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Checkbox.Indicator.Props) {
  return <Checkbox.Indicator className={clsx('flex data-unchecked:hidden', className)} {...props} />;
}
```

```tsx
/* combobox.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Combobox } from '@base-ui/react/combobox';

export function Root(props: Combobox.Root.Props<any, any>) {
  return <Combobox.Root {...props} />;
}

export const Input = React.forwardRef<HTMLInputElement, Combobox.Input.Props>(function Input(
  { className, ...props }: Combobox.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Combobox.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-full border-0 bg-white pl-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 outline-none placeholder:text-neutral-500 dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function InputGroup({ className, ...props }: Combobox.InputGroup.Props) {
  return (
    <Combobox.InputGroup
      className={clsx(
        'relative h-8 w-64 border border-neutral-950 bg-white focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-neutral-950 dark:focus-within:outline-white dark:border-white dark:bg-neutral-950 [&>input]:pr-[2.5rem] has-[.combobox-clear]:[&>input]:pr-[calc(0.5rem+2rem*2)]',
        className,
      )}
      {...props}
    />
  );
}

export function Clear({ className, ...props }: Combobox.Clear.Props) {
  return (
    <Combobox.Clear
      className={clsx('combobox-clear flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)}
      {...props}
    >
      <XIcon />
    </Combobox.Clear>
  );
}

export function Trigger({ className, ...props }: Combobox.Trigger.Props) {
  return <Combobox.Trigger className={clsx('flex h-full w-6 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Portal(props: Combobox.Portal.Props) {
  return <Combobox.Portal {...props} />;
}

export function Positioner({ className, ...props }: Combobox.Positioner.Props) {
  return <Combobox.Positioner className={clsx('outline-none', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Combobox.Popup.Props) {
  return (
    <Combobox.Popup
      className={clsx(
        'w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0_rgb(0_0_0/12%)] transition-[scale,opacity] duration-100 data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function Empty({ className, children, ...props }: Combobox.Empty.Props) {
  return (
    <Combobox.Empty {...props}>
      {children ? <div className={clsx('py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400', className)}>{children}</div> : null}
    </Combobox.Empty>
  );
}

export function List({ className, ...props }: Combobox.List.Props) {
  return (
    <Combobox.List
      className={clsx('outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[min(22.5rem,var(--available-height))] data-empty:p-0', className)}
      {...props}
    />
  );
}

export function Item({ className, ...props }: Combobox.Item.Props) {
  return (
    <Combobox.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 p-2 text-sm leading-4 outline-none select-none data-highlighted:relative data-highlighted:z-0 data-highlighted:text-white data-highlighted:before:absolute data-highlighted:before:inset-0 data-highlighted:before:z-[-1] data-highlighted:before:bg-neutral-950 dark:data-highlighted:text-neutral-950 dark:data-highlighted:before:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Combobox.ItemIndicator.Props) {
  return <Combobox.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function CaretDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" {...props} style={{ display: 'block', ...props.style }}>
      <path d="M12 6H4l4 4.5z" />
    </svg>
  );
}

function XIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      stroke="currentColor"
      strokeLinecap="square"
      strokeLinejoin="round"
      {...props}
      style={{ display: 'block', ...props.style }}
    >
      <path d="m4.5 4.5 7 7m-7 0 7-7" />
    </svg>
  );
}
```

```tsx
/* field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Field } from '@base-ui/react/field';

export function Root({ className, ...props }: Field.Root.Props) {
  return <Field.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Label({ className, ...props }: Field.Label.Props) {
  return (
    <Field.Label
      className={clsx(
        'text-sm font-bold text-neutral-950 has-[[role="checkbox"]]:flex has-[[role="checkbox"]]:items-center has-[[role="checkbox"]]:gap-2 has-[[role="checkbox"]]:font-normal has-[[role="radio"]]:flex has-[[role="radio"]]:items-center has-[[role="radio"]]:gap-2 has-[[role="radio"]]:font-normal has-[[role="switch"]]:flex has-[[role="switch"]]:items-center dark:text-white',
        className,
      )}
      {...props}
    />
  );
}

export function Description({ className, ...props }: Field.Description.Props) {
  return <Field.Description className={clsx('text-sm text-neutral-600 dark:text-neutral-400', className)} {...props} />;
}

export const Control = React.forwardRef<HTMLInputElement, Field.Control.Props>(function FieldControl(
  { className, ...props }: Field.Control.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <Field.Control
      ref={forwardedRef}
      className={clsx(
        'h-8 w-full max-w-xs border border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 placeholder:text-neutral-500 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:placeholder:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
});

export function Error({ className, ...props }: Field.Error.Props) {
  return <Field.Error className={clsx('text-sm text-red-700 dark:text-red-400', className)} {...props} />;
}

export function Item(props: Field.Item.Props) {
  return <Field.Item {...props} />;
}
```

```tsx
/* fieldset.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Fieldset } from '@base-ui/react/fieldset';

export function Root(props: Fieldset.Root.Props) {
  return <Fieldset.Root {...props} />;
}

export function Legend({ className, ...props }: Fieldset.Legend.Props) {
  return <Fieldset.Legend className={clsx('text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}
```

```tsx
/* number-field.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { NumberField } from '@base-ui/react/number-field';

export function Root({ className, ...props }: NumberField.Root.Props) {
  return <NumberField.Root className={clsx('flex flex-col items-start gap-1', className)} {...props} />;
}

export function Group({ className, ...props }: NumberField.Group.Props) {
  return <NumberField.Group className={clsx('flex h-8', className)} {...props} />;
}

export function Decrement({ className, ...props }: NumberField.Decrement.Props) {
  return (
    <NumberField.Decrement
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}

export const Input = React.forwardRef<HTMLInputElement, NumberField.Input.Props>(function Input(
  { className, ...props }: NumberField.Input.Props,
  forwardedRef: React.ForwardedRef<HTMLInputElement>,
) {
  return (
    <NumberField.Input
      ref={forwardedRef}
      className={clsx(
        'h-full w-16 rounded-none border-y border-neutral-950 bg-white px-2 text-sm any-pointer-coarse:text-base font-normal text-neutral-950 tabular-nums focus:z-1 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:bg-neutral-950 dark:text-white',
        className,
      )}
      {...props}
    />
  );
});

export function Increment({ className, ...props }: NumberField.Increment.Props) {
  return (
    <NumberField.Increment
      className={clsx(
        'flex h-full w-8 items-center justify-center rounded-none border border-neutral-950 bg-white bg-clip-padding text-neutral-950 outline-0 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 focus-visible:z-1 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* radio.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Radio } from '@base-ui/react/radio';

export function Root({ className, ...props }: Radio.Root.Props) {
  return (
    <Radio.Root
      className={clsx(
        'flex size-4 shrink-0 items-center justify-center rounded-full border border-neutral-950 bg-white p-0 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 data-checked:text-white dark:border-white dark:bg-neutral-950 dark:text-neutral-950 dark:data-checked:bg-white dark:data-checked:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function Indicator({ className, ...props }: Radio.Indicator.Props) {
  return <Radio.Indicator className={clsx('flex items-center justify-center data-unchecked:hidden before:size-2 before:rounded-full before:bg-current', className)} {...props} />;
}
```

```tsx
/* select.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Select } from '@base-ui/react/select';

export function Root(props: Select.Root.Props<any>) {
  return <Select.Root {...props} />;
}

export function Label({ className, ...props }: Select.Label.Props) {
  return <Select.Label className={clsx('cursor-default text-sm font-bold text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Trigger({ className, ...props }: Select.Trigger.Props) {
  return (
    <Select.Trigger
      className={clsx(
        'flex h-8 min-w-40 cursor-default items-center justify-between gap-3 border border-neutral-950 bg-white pl-2 pr-1 text-sm font-normal text-neutral-950 select-none hover:not-data-disabled:bg-neutral-100 active:not-data-disabled:bg-neutral-200 data-disabled:border-neutral-500 data-disabled:text-neutral-500 data-pressed:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950 dark:text-white dark:hover:not-data-disabled:bg-neutral-800 dark:active:not-data-disabled:bg-neutral-700 dark:data-disabled:border-neutral-400 dark:data-disabled:text-neutral-400 dark:data-pressed:bg-neutral-800',
        className,
      )}
      {...props}
    />
  );
}

export function Value({ className, ...props }: Select.Value.Props) {
  return <Select.Value className={clsx('data-placeholder:text-neutral-500 dark:data-placeholder:text-neutral-400', className)} {...props} />;
}

export function Icon(props: Select.Icon.Props) {
  return <Select.Icon {...props} />;
}

export function Portal(props: Select.Portal.Props) {
  return <Select.Portal {...props} />;
}

export function Positioner({ className, ...props }: Select.Positioner.Props) {
  return <Select.Positioner className={clsx('outline-none select-none z-10', className)} sideOffset={4} {...props} />;
}

export function Popup({ className, ...props }: Select.Popup.Props) {
  return (
    <Select.Popup
      className={clsx(
        'group min-w-(--anchor-width) origin-(--transform-origin) border border-neutral-950 bg-white bg-clip-padding text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[side=none]:min-w-[calc(var(--anchor-width)+1.75rem)] data-[side=none]:translate-y-px data-ending-style:scale-[0.98] data-ending-style:opacity-0 data-[side=none]:data-ending-style:transition-none data-starting-style:scale-[0.98] data-starting-style:opacity-0 data-[side=none]:data-starting-style:scale-100 data-[side=none]:data-starting-style:opacity-100 data-[side=none]:data-starting-style:transition-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none',
        className,
      )}
      {...props}
    />
  );
}

export function ScrollUpArrow({ className, ...props }: Select.ScrollUpArrow.Props) {
  return (
    <Select.ScrollUpArrow
      className={clsx(
        "top-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute data-[side=none]:before:-top-full before:left-0 before:h-full before:w-full before:content-[''] dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function ScrollDownArrow({ className, ...props }: Select.ScrollDownArrow.Props) {
  return (
    <Select.ScrollDownArrow
      className={clsx(
        "bottom-0 z-1 flex h-4 w-full cursor-default items-center justify-center bg-white text-center text-xs before:absolute before:left-0 before:h-full before:w-full before:content-[''] data-[side=none]:before:-bottom-full dark:bg-neutral-950",
        className,
      )}
      {...props}
    />
  );
}

export function List({ className, ...props }: Select.List.Props) {
  return <Select.List className={clsx('relative max-h-(--available-height) overflow-y-auto py-1 scroll-py-6', className)} {...props} />;
}

export function Item({ className, ...props }: Select.Item.Props) {
  return (
    <Select.Item
      className={clsx(
        'grid cursor-default grid-cols-[1rem_1fr] items-center gap-2 py-1.5 pr-4 pl-2.5 text-sm outline-none select-none group-data-[side=none]:pr-12 data-highlighted:bg-neutral-950 data-highlighted:text-white dark:data-highlighted:bg-white dark:data-highlighted:text-neutral-950',
        className,
      )}
      {...props}
    />
  );
}

export function ItemIndicator({ className, ...props }: Select.ItemIndicator.Props) {
  return <Select.ItemIndicator className={clsx('col-start-1', className)} {...props} />;
}

export function ItemText({ className, ...props }: Select.ItemText.Props) {
  return <Select.ItemText className={clsx('col-start-2', className)} {...props} />;
}
```

```tsx
/* slider.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Slider } from '@base-ui/react/slider';

export function Root({ className, ...props }: Slider.Root.Props<any>) {
  return <Slider.Root className={clsx('grid grid-cols-2', className)} {...props} />;
}

export function Value({ className, ...props }: Slider.Value.Props) {
  return <Slider.Value className={clsx('text-sm font-normal text-neutral-950 dark:text-white', className)} {...props} />;
}

export function Control({ className, ...props }: Slider.Control.Props) {
  return <Slider.Control className={clsx('flex col-span-2 touch-none items-center py-3 select-none', className)} {...props} />;
}

export function Track({ className, ...props }: Slider.Track.Props) {
  return <Slider.Track className={clsx('h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800', className)} {...props} />;
}

export function Indicator({ className, ...props }: Slider.Indicator.Props) {
  return <Slider.Indicator className={clsx('bg-neutral-950 select-none dark:bg-white', className)} {...props} />;
}

export function Thumb({ className, ...props }: Slider.Thumb.Props) {
  return (
    <Slider.Thumb
      className={clsx(
        'size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```tsx
/* switch.tsx */
import * as React from 'react';
import clsx from 'clsx';
import { Switch } from '@base-ui/react/switch';

export function Root({ className, ...props }: Switch.Root.Props) {
  return (
    <Switch.Root
      className={clsx(
        'flex h-5 w-9 shrink-0 border border-neutral-950 bg-white p-0.5 transition-colors duration-150 ease-[ease] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-checked:bg-neutral-950 dark:border-white dark:bg-neutral-950 dark:data-checked:bg-white',
        className,
      )}
      {...props}
    />
  );
}

export function Thumb({ className, ...props }: Switch.Thumb.Props) {
  return (
    <Switch.Thumb
      className={clsx(
        'size-3.5 bg-neutral-950 transition-[translate,background-color] duration-150 ease-[ease] data-checked:translate-x-4 data-checked:bg-white dark:bg-white dark:data-checked:bg-neutral-950',
        className,
      )}
      {...props}
    />
  );
}
```

```ts
/* stencil-tanstack-form.ts */
import { FormApi, FieldApi, revalidateLogic, type DeepKeys, type ValidationError } from '@tanstack/form-core';
import { createForm, defaultValues, fieldNames, type FormValues } from './stencil-form';
import { connectField } from './stencil-form-events';
import { connectToasts } from './stencil-toast';

export function mount(container: HTMLElement, themed = false) {
  const elements = createForm(container, { externalValidation: true, nativeForm: true, themed });
  const toasts = connectToasts(elements.provider, elements.toastViewport, themed);
  const form = new FormApi({
    defaultValues,
    onSubmit: ({ value }) => {
      toasts.submit(value);
    },
    validationLogic: revalidateLogic({ mode: 'submit', modeAfterSubmission: 'change' }),
    validators: {
      onDynamic: ({ value }) => {
        const errors: Partial<Record<DeepKeys<FormValues>, ValidationError>> = {};
        (['serverName', 'region', 'containerImage', 'serverType', 'numOfInstances'] as const).forEach(name => {
          if (!value[name]) errors[name] = 'This is a required field.';
        });
        if (value.serverName && value.serverName.length < 3) errors.serverName = 'At least 3 characters.';
        return Object.keys(errors).length ? { form: errors, fields: errors } : undefined;
      },
    },
  });
  const unmountForm = form.mount();
  const cleanupFields = fieldNames.map(name => {
    const field = new FieldApi({ form, name });
    const unmountField = field.mount();
    const connection = connectField(elements, name, field.handleChange, field.handleBlur);
    const update = () =>
      connection.update({
        value: field.state.value,
        invalid: !field.state.meta.isValid,
        dirty: field.state.meta.isDirty,
        touched: field.state.meta.isTouched,
        error: field.state.meta.errors.join(','),
      });
    const subscription = field.store.subscribe(update);
    update();
    return () => {
      subscription.unsubscribe();
      connection.destroy();
      unmountField();
    };
  });
  const submit = (event: Event) => {
    event.preventDefault();
    void form.handleSubmit();
  };
  elements.form.addEventListener('submit', submit);
  return () => {
    elements.form.removeEventListener('submit', submit);
    cleanupFields.forEach(cleanup => cleanup());
    unmountForm();
    toasts.destroy();
    elements.destroy();
  };
}
```

```ts
/* stencil-form-events.ts */
import type { FormElements, FormValues } from './stencil-form';

export interface FieldState {
  value: FormValues[keyof FormValues];
  invalid: boolean;
  touched: boolean;
  dirty: boolean;
  error?: string;
}

/** The form library owns values and validation; the elements own their UI and ARIA. */
export function connectField(elements: FormElements, name: keyof FormValues, onChange: (value: any) => void, onBlur: () => void, inputRef?: (element: HTMLElement | null) => void) {
  const field = elements.fields[name];
  const control = elements.controls[name];
  const refTarget = name === 'scalingThreshold' ? field.querySelector('fs-slider-thumb')! : name === 'allowedNetworkProtocols' ? field.querySelector('fs-checkbox-root')! : control;
  const error = elements.errors[name];
  // Keep the authored text node: Field.Error can be offline while valid.
  const message = error?.querySelector('span');
  const valueProperty = name === 'restartOnFailure' ? 'checked' : 'value';
  const eventName = name === 'restartOnFailure' ? 'checkedChange' : 'valueChange';
  const change = (event: Event) => {
    if (event.target === control) onChange((event as CustomEvent).detail[valueProperty]);
  };
  control.addEventListener(eventName, change);
  if (name === 'scalingThreshold') control.addEventListener('valueCommitted', change);
  const blur = () => onBlur();
  field.addEventListener('focusout', blur);
  if (inputRef) {
    if (name === 'numOfInstances') inputRef(field.querySelector('fs-number-field-input'));
    else Reflect.set(refTarget, 'inputRef', inputRef);
  }
  return {
    update(state: FieldState) {
      Reflect.set(control, valueProperty, state.value);
      field.invalid = state.invalid;
      field.touched = state.touched;
      field.dirty = state.dirty;
      if (message) message.textContent = state.error ?? '';
      if (error) error.match = state.invalid;
    },
    destroy() {
      control.removeEventListener(eventName, change);
      control.removeEventListener('valueCommitted', change);
      field.removeEventListener('focusout', blur);
      if (inputRef) {
        Reflect.set(refTarget, 'inputRef', undefined);
        inputRef(null);
      }
    },
  };
}
```

```ts
/* stencil-toast.ts */
import { createToastManager, type ToastObject } from 'finesoft-components/toast';
import type { Components } from 'finesoft-components';

const toastHTML = `
<fs-toast-root class="[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] mr-0 w-full origin-bottom transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 select-none dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-[''] data-ending-style:opacity-0 data-limited:opacity-0 data-starting-style:transform-[translateY(150%)] [&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:transform-[translateY(150%)] data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+150%))] data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))] data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-150%))] h-(--height) [transition:transform_0.5s_cubic-bezier(0.22,1,0.36,1),opacity_0.5s,height_0.15s]">
  <fs-toast-content class="h-full overflow-hidden p-3 transition-opacity duration-250">
    <fs-toast-title class="text-sm font-bold"></fs-toast-title>
    <fs-toast-description class="text-sm text-neutral-700 dark:text-neutral-300"></fs-toast-description>
    <div class="mt-2 border border-neutral-950 p-2 text-xs select-text dark:border-white" data-base-ui-swipe-ignore="true">
      <pre class="whitespace-pre-wrap"></pre>
    </div>
    <fs-toast-close class="absolute top-3 right-3 flex size-8 items-center justify-center border-0 bg-transparent p-0 text-neutral-950 hover:bg-neutral-100 active:bg-neutral-200 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:bg-neutral-800 dark:active:bg-neutral-700" aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

const themedToastHTML = `
<fs-toast-root data-fs-variant="rich">
  <fs-toast-content>
    <fs-toast-title></fs-toast-title>
    <fs-toast-description></fs-toast-description>
    <div class="handbook-form-submitted-values" data-base-ui-swipe-ignore="true">
      <pre></pre>
    </div>
    <fs-toast-close aria-label="Close">
      <svg width="16" height="16" viewbox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" style="display:block">
        <path d="m2.5 2.5 11 11m-11 0 11-11"></path>
      </svg>
    </fs-toast-close>
  </fs-toast-content>
</fs-toast-root>
`;

export function connectToasts(provider: HTMLElement & Components.FsToastProvider, viewport: Element, themed = false) {
  const manager = createToastManager();
  const roots = new Map<string, HTMLElement & Components.FsToastRoot>();
  function update(event: CustomEvent<ToastObject[]>) {
    const toasts = event.detail;
    for (const [id, root] of roots) {
      if (!toasts.some(toast => toast.id === id)) {
        root.remove();
        roots.delete(id);
      }
    }
    for (const toast of toasts) {
      let root = roots.get(toast.id);
      if (!root) {
        const template = provider.ownerDocument.createElement('template');
        template.innerHTML = themed ? themedToastHTML : toastHTML;
        root = template.content.firstElementChild as HTMLElement & Components.FsToastRoot;
        root.toast = toast;
        root.querySelector('pre')!.textContent = JSON.stringify(toast.data, null, 2);
        roots.set(toast.id, root);
        viewport.append(root);
      } else {
        root.toast = toast;
      }
    }
  }
  provider.addEventListener('toastsChange', update as EventListener);
  provider.toastManager = manager;
  return {
    submit: (data: unknown) => manager.add({ title: 'Form submitted', description: 'The form contains these values:', data: data as Record<string, unknown> }),
    destroy: () => provider.removeEventListener('toastsChange', update as EventListener),
  };
}
```

### Initialize the form

Create a form instance with the `useForm` hook, assigning the initial value of each field by their name in the `defaultValues` parameter:

```tsx title="Initialize a form instance"
import { useForm } from '@tanstack/react-form';

interface FormValues {
  username: string;
  email: string;
}

const defaultValues: FormValues = {
  username: '',
  email: '',
};

{/* @highlight-start */}
/* useForm returns a form instance */
const form = useForm<FormValues>({
{/* @highlight-end */}
  defaultValues,
});
```

### Integrate components

Use the `<form.Field>` component from the form instance to integrate with Base UI components using the `children` prop, forwarding the various `field` render props to the appropriate part:

```tsx title="Integrating TanStack Form with Base UI components"
import { useForm } from '@tanstack/react-form';
import { Field } from '@base-ui/react/field';

const form = useForm(/* defaultValues, other parameters */)

<form>
  {/* @highlight-start */}
  <form.Field
    name="username"
    children={(field) => (
    // @highlight-end
      <Field.Root
        {/* @highlight-start */}
        name={field.name} {/* @highlight-text "field.name" */}
        invalid={!field.state.meta.isValid} {/* @highlight-text "isValid" */}
        dirty={field.state.meta.isDirty} {/* @highlight-text "isDirty" */}
        touched={field.state.meta.isTouched} {/* @highlight-text "isTouched" */}
        {/* @highlight-end */}
      >
        <Field.Label>Username</Field.Label>
        <Field.Control
          {/* @highlight-start */}
          value={field.state.value} {/* @highlight-text "value" */}
          onValueChange={field.handleChange} {/* @highlight-text "handleChange" */}
          onBlur={field.handleBlur} {/* @highlight-text "handleBlur" */}
          {/* @highlight-end */}
          placeholder="e.g. bob276"
        />

        {/* @highlight-start */}
        <Field.Error match={!field.state.meta.isValid}> {/* @highlight-text "isValid" */}
        {/* @highlight-end */}
          {field.state.meta.errors.join(',')}
        </Field.Error>
      </Field.Root>
    )}
  />
</form>
```

The Base UI `<Form>` component is not needed when using TanStack Form.

### Form validation

To configure a native `<form>`-like validation strategy:

1. Use the additional `revalidateLogic` hook and pass it to `useForm`.
2. Pass a validation function to the `validators.onDynamic` prop on `<form.Field>` that returns an error object with keys corresponding to the field `name`s.

This validates all fields when the first submission is attempted, and revalidates any invalid fields when their values change again.

```tsx title="Form-level validators"
import { useForm, revalidateLogic } from '@tanstack/react-form'; // @highlight-text "revalidateLogic"

const form = useForm({
  defaultValues: {
    username: '',
    email: '',
  },
  {/* @highlight-start */}
  validationLogic: revalidateLogic({ {/* @highlight-text "revalidateLogic" */}
  {/* @highlight-end */}
    mode: 'submit',
    modeAfterSubmission: 'change',
  }),
  validators: {
    // @highlight-start
    onDynamic: ({ value: formValues }) => { // @highlight-text "onDynamic"
    // @highlight-end
      const errors = {};

      if (!formValues.username) {
        errors.username = 'Username is required.';
      } else if (formValues.username.length < 3) {
        errors.username = 'At least 3 characters.';
      }

      if (!formValues.email) {
        errors.email = 'Email is required.';
      } else if (!isValidEmail(formValues.email)) {
        errors.email = 'Invalid email address.';
      }

      return { form: errors, fields: errors };
    },
  },
});
```

### Field validation

You can pass additional validator functions to individual `<form.Field>` components to add validations on top of the form-level validators:

```tsx title="Field-level validators"
import { Field } from '@base-ui/react/field';
import { useForm } from '@tanstack/react-form';

const form = useForm();

<form.Field
  name="username"
  {/* @highlight-start */}
  validators={{
    onChangeAsync: async ({ value: username }) => {
      const result = await fetch(
        /* check the availability of a username from an external API */
      );

      return result.success ? undefined : `${username} is not available.`
    }
  }}
  {/* @highlight-end */}
  children={(field) => (
    <Field.Root name={field.name} /* forward the field props */ />
  )}
>
```

### Submitting data

To submit the form:

1. Pass a submit handler function to the `onSubmit` parameter of `useForm`.
2. Call `form.handleSubmit()` from an event handler such as form `onSubmit` or `onClick` on a button.

```tsx title="Form submission handler"
import { useForm } from '@tanstack/react-form';

const form = useForm({
  // @highlight-start
  onSubmit: async ({ value: formValues }) => {
    /* prettier-ignore */
    await fetch(/* POST the `formValues` to an external API */);
  },
  {/* @highlight-end */}
});

<form
  onSubmit={(event) => {
    event.preventDefault();
    // @highlight-start
    form.handleSubmit(); // @highlight-text "form.handleSubmit()"
    // @highlight-end
  }}
>
  {/* form fields */}
  {/* @highlight-start */}
  <button type="submit">Submit</button>
  {/* @highlight-end */}
</form>;
```
