fabian-hiller / modular-forms

The modular and type-safe form library for SolidJS, Qwik and Preact
https://modularforms.dev
MIT License
983 stars 53 forks source link

Better kobalte RadioGroup example attached here; fixes bug #229

Open dsmurl opened 1 month ago

dsmurl commented 1 month ago

// This is to move the Kobalte.ItemControl element inside the Kobalte.ItemLabel which allows the circle thing to be clickable too which is excpected via users. // Radio Group section from file -> website/src/routes/(layout)/[framework]/guides/kobalte.mdx:


## Radio Group

For the selection of a single text value via radio buttons we use the <a href="https://kobalte.dev/docs/core/components/radio-group" target="_blank" rel="noreferrer">Radio Group</a> component of Kobalte. Add the file `RadioGroup.tsx` to your components directory and copy the following code into it:

```tsx
import { RadioGroup as Kobalte } from '@kobalte/core';
import { type JSX, Show, splitProps, For } from 'solid-js';

type RadioGroupProps = {
  name: string;
  label?: string | undefined;
  options: { label: string; value: string }[];
  value: string | undefined;
  error: string;
  required?: boolean | undefined;
  disabled?: boolean | undefined;
  ref: (element: HTMLInputElement | HTMLTextAreaElement) => void;
  onInput: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, InputEvent>;
  onChange: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, Event>;
  onBlur: JSX.EventHandler<HTMLInputElement | HTMLTextAreaElement, FocusEvent>;
};

export function RadioGroup(props: RadioGroupProps) {
  const [rootProps, inputProps] = splitProps(
    props,
    ['name', 'value', 'required', 'disabled'],
    ['ref', 'onInput', 'onChange', 'onBlur']
  );
  return (
    <Kobalte.Root
      {...rootProps}
      validationState={props.error ? 'invalid' : 'valid'}
    >
      <Show when={props.label}>
        <Kobalte.Label>{props.label}</Kobalte.Label>
      </Show>
      <div>
        <For each={props.options}>
          {(option) => (
            <Kobalte.Item value={option.value}>
              <Kobalte.ItemInput {...inputProps} />
              <Kobalte.ItemLabel>
                <Kobalte.ItemControl>
                  <Kobalte.ItemIndicator />
                </Kobalte.ItemControl>
                {option.label}
              </Kobalte.ItemLabel>
            </Kobalte.Item>
          )}
        </For>
      </div>
      <Kobalte.ErrorMessage>{props.error}</Kobalte.ErrorMessage>
    </Kobalte.Root>
  );
}

After adding your own styles, you can use the component together with Modular Forms as follows:

<Field name="framework">
  {(field, props) => (
    <RadioGroup
      {...props}
      label="Framework"
      options={[
        { label: 'SolidJS', value: 'solid' },
        { label: 'Qwik', value: 'qwik' },
        { label: 'Preact', value: 'preact' },
      ]}
      value={field.value}
      error={field.error}
      required
    />
  )}
</Field>
fabian-hiller commented 1 month ago

Are you interested in creating a PR or should I fix it myself?