This task covers determining how we will implement a Field component in Codex. There are several implementation routes we could take and we should evaluate them carefully in terms of end user experience, developer experience, and library maintenance.
---
## Background
The Field component is still being designed (see T330419), but it will likely contain some or all of these features:
- A semantic label, which is connected to the input via an aria attribute for accessibility support
- "Optional" indicator (fields will be required by default, but can be marked as optional)
- A tooltip or popup next to the label
- A description below the label
- An input (e.g. TextInput), control (e.g. ToggleSwitch), or input group (Radio group)
- Helper text below the input
- A character counter for some inputs (e.g. TextArea)
- An inline validation message
- Field actions (e.g. a button to delete the field)
Here is a work-in-progress design exploration:
{F36885110}
---
## Implementation options
There are 2 main paths we're consider for implementation, detailed below. For each, I've created a proof of concept that implements a few of the Field features (semantic label for both inputs and input groups, helper text, inline validation and error styles).
### Option 1: Standalone Field component used alongside input/control components
Option 1 is a Field component that developer users would use to wrap an input or control component (or group). It would contain a slot for the input/control. The dev user would pass field props into the Field component, but continue to pass input props into the input component.
- Demos:
- [[ https://893010--wikimedia-codex.netlify.app/components/demos/field.html#text-input-field | Single input ]]
- [[ https://893010--wikimedia-codex.netlify.app/components/demos/field.html#radio-group | RadioGroup ]]
- [[ https://893010--wikimedia-codex.netlify.app/components/demos/field.html#complex-field-with-two-inputs | Field with two inputs ]] (which each have an associated Label component)
- [[ https://893010--wikimedia-codex.netlify.app/components/demos/field.html#fieldset-with-nested-fields | Field with two nested Fields ]] (so that each input in the Fieldset can have its own description, error message, etc.)
- [[ https://gerrit.wikimedia.org/r/c/design/codex/+/893010 | Patch ]]
Pros:
- Field features are documented in a single place (the [[ https://893010--wikimedia-codex.netlify.app/components/demos/field.html | Field demo page ]])
- Input groups can be handled internally; no need for new RadioGroup and CheckboxGroup components
- Encourages composition for maximum flexibility. Inputs/controls can be used with or without the Field component, so simple inputs could be composed into more complex ones. Label is a separate component that can be used on its own without all the other Field stuff.
- We're providing simpler building blocks that will allow people to compose their own solutions
Cons:
- Dev users have to use 2 components (Field + the input component)
- Not including the Field features by default inside input/control components could discourage devs from adding important elements like semantic labels. We would need to consider how to effectively document a11y recommendations.
- More difficult to add Field features that only apply to some inputs, e.g. character count. Such features should be limited (character count is the only one we've identified), but their implementation is not ideal with this option.
### Option 2: Internal Field component used inside input/control components
Option 2 would integrate the Field component within input/control components, so that they would internally use the Field component, rather than the dev user using it. Dev users would only use the input/control component itself, and pass both field and input props into that component. That said, the Field component would be available to dev users if they needed to build their own custom input/control (but most dev users would not need to use it directly).
- Demos:
- Single components ([[ https://893011--wikimedia-codex.netlify.app/components/demos/text-input.html#field | TextInput ]], [[ https://893011--wikimedia-codex.netlify.app/components/demos/field.html#select | Select ]]),
- [[ https://893011--wikimedia-codex.netlify.app/components/demos/radio.html#radio-group | RadioGroup ]]
- [[ https://893011--wikimedia-codex.netlify.app/components/demos/field.html#complex-field | Fieldset with two inputs ]]
- [[ https://893011--wikimedia-codex.netlify.app/components/demos/field.html#field-with-nested-fields | Field with two nested Fields ]]
- [[ https://gerrit.wikimedia.org/r/c/design/codex/+/893011 | Patch ]]
Pros:
- Dev users only need to use a single component
- Encourages use of Field features like semantic labels
- More easily enables us to apply input-specific Field features, like character count, which only applies to TextInput and TextArea
Cons:
- Could limit or discourage composition. Technically, you could still compose inputs into a more complex input and use that within the Field component, but this is not the "happy path" and may not be as clear with this implementation.
- We would probably need to have RadioGroup and CheckboxGroup components to properly handle semantic labeling of these things. More components to know about and maintain.
- Documentation may be less clear or redundant since we'd need to document Field features on every input/control page, and field-related props would be included in the props table for all of those components (could be noisy)
- Potentially more complex from a library maintenance standpoint, because we'd need to guarantee that things like nested fields would work (there's a lot of props, providing, and injecting going on to get everything to work right). See the nested fields demo for an example - the field description of the Lookup lives within the TextInput component, so the Lookup's menu is output below the entire TextInput. We'd need to account for issues like this, and it might make it harder for other devs to compose their own fields.
---
## Acceptance criteria
- [] Discuss these options with stakeholders
- [] Choose a path forward