digdir / designsystemet

Designsystemet
https://designsystemet.no
MIT License
80 stars 37 forks source link

FormField components #2311

Open mrosvik opened 2 months ago

mrosvik commented 2 months ago

Some designsystems use generic form classes/components, usually called form-group or form-field for their form components to have consistent placement of label, descriptions and such around an input/textarea/select element.

Notes:

This could be possible if we split up Textfield into multiple sub-components or generic form scaffolding components.

More generic, example from Radix:

  <Form.Root>
    <Form.Field>
      <Form.Label />
      <Form.Control asChild>
        <input className="Input" type="email" required />
      </Form.Control>
      <Form.Message />
      <Form.ValidityState />
    </Form.Field>

    <Form.Message />
    <Form.ValidityState />

    <Form.Submit />
  </Form.Root>

Or more scoped, Example from Ark UI

import { Field } from '@ark-ui/react'

export const Input = () => {
  return (
    <Field.Root>
      <Field.Label>Label</Field.Label>
      <Field.Input />
      <Field.HelperText>Some additional Info</Field.HelperText>
      <Field.ErrorText>Error Info</Field.ErrorText>
    </Field.Root>
  )
}
### Tasks
- [ ] https://github.com/digdir/designsystemet/issues/2713
- [ ] https://github.com/digdir/designsystemet/issues/2715
- [ ] https://github.com/digdir/designsystemet/issues/2664
- [ ] #2708
- [ ] Thorough testing of fieldObserver utility
- [ ] Remove ds-reset.css for form elements
- [ ] Combobox?
- [x] useCheckbox hook for indeterminate, multiple checked and error #2712
- [x] useRadio hook for error and same name #2712
- [x] Select #2709
- [x] Field.Counter #2717
- [ ] https://github.com/digdir/designsystemet/issues/1943
- [ ] https://github.com/digdir/designsystemet/issues/2459
- [ ] https://github.com/digdir/designsystemet/issues/2640
- [ ] https://github.com/digdir/designsystemet/issues/2666
- [ ] https://github.com/digdir/designsystemet/issues/2669
- [ ] https://github.com/digdir/designsystemet/pull/2607
- [ ] Create shard documentation for form compoents
eirikbacker commented 2 months ago

This is a React specific issue. I would argue, that we should in general skip the .Root level, and just do for instance:

<Accordion>
  <Accordion.Heading></Accordion.Heading>
  <Accordion.Content></Accordion.Content>
</Accordion>

When the base component is rendering a actual HTML element, as this clean and a very common pattern: https://www.patterns.dev/react/compound-pattern/

When using .Root (or .Provider), the common pattern is that this is an indication to the consumer that the React element does not render any HTML, but is there more to provide a functional context: https://kyleshevlin.com/compound-components/ https://medium.com/@win.le/react-compound-component-with-typescript-d7944ac0d1d6

This separation makes it easier to resonate and exemplify about how our design system translates between React and HTML and other frameworks, as the functional useContext is mostly a React pattern.

That said, I think we can maybe flip the question, and ask;

Could the interface then be something like:

<Field>
  <Label>Label</Label>
  <Input />
  <Field.Help>Some additional Info</Field.Help>
  <Field.Error>Error Info</Field.Error>
</Field.Root>

...where <Label> and <Input> is not prefixed - aligning with native elements and HTML standard, and indicating that Field is optional just like in pure HTML? Pure HTML-example of the same:

<ds-field>
  <label>Label</label>
  <input />
  <ds-field-help>Some additional Info</ds-field-help>
  <ds-field-error>Error Info</ds-field-error>
</ds-field>

(dropping form from the name as input-like elements does not actually require being placed inside a form).