UNPKG

@octopusdeploy/design-system-components

Version:
138 lines (91 loc) 5.59 kB
# Form Components ## Packages Core form primitives live in `@octopusdeploy/design-system-components`. Octopus-specific form fields (`Select`, `Slug`, `TimeSpanSelector`, `NumberPicker`) live in `@octopusdeploy/design-system-octopus-components`. All exports are flat — no namespace prefixes. ## Text input Use `TextField` from `@octopusdeploy/design-system-components` for free-text input. ```tsx import { TextField } from "@octopusdeploy/design-system-components"; <TextField label="Name" value={name} onChange={setName} error={nameError} /> ``` Required props: `label`, `value`, `onChange`. Never pass `className` or `style`. `@octopusdeploy/design-system-octopus-components` also exports a `Text` component that wraps `TextField` with an Octopus-specific label strategy. Prefer `TextField` unless you specifically need that label strategy behaviour. ## Number input Use `NumberField` from `@octopusdeploy/design-system-components`. ❌ Don't use `Number` or `NumberPicker` from octopus-components — both are deprecated. ## Select / dropdown Use `Select` from `@octopusdeploy/design-system-octopus-components`. ❌ Don't use `DeprecatedSelect` — it is a class-based component and has no place in new code. ## Switch — instant changes only `Switch` is exclusively for changes that take effect immediately without a submit action. It is never a form field that participates in form submission. ✅ Correct: toggling a feature on/off inline, enabling/disabling a setting that saves immediately ❌ Wrong: using `Switch` inside a form where the user clicks a Save button ```tsx import { Switch } from "@octopusdeploy/design-system-components"; // With label — accessibleName is optional <Switch label="Enable feature" value={enabled} onChange={setEnabled} /> // Without visible label — accessibleName is required <Switch accessibleName="Enable notifications" value={enabled} onChange={setEnabled} /> ``` ## Checkbox and RadioButton Use `Checkbox`, `CheckboxNew`, and `RadioButton` from `@octopusdeploy/design-system-components`. Check JSDoc for any props marked `@deprecated` before using. ## Form composition Forms should use design system form components exclusively. Do not build custom input wrappers around native `<input>`, `<select>`, or `<textarea>` elements. Field descriptions, error states, and labels are built into each field component. Pass `error` and `description` as props rather than rendering supplementary text outside the component. ## Layout **Default to a single-column layout.** The majority of forms should stack fields vertically, top-to-bottom, left-aligned. Labels sit above inputs. **Multi-column layouts: use sparingly and max 2 columns.** A second column is only appropriate when fields are closely related and naturally grouped side-by-side (e.g. first name and last name). Do not use more than 2 columns. Multi-column layouts must stack to single-column on smaller viewports. ❌ Don't use 2 columns just to reduce vertical space — this increases cognitive load and makes the form harder to complete in order. ✅ Do use 2 columns when fields are semantically paired and the relationship is obvious. Set a sensible min/max width on the form container so fields don't stretch to fill very wide viewports — excessively wide inputs are harder to read and scan. **Field sizing** should reflect the expected input length. A postcode field should be narrow; a URL field should be wide. Avoid large size jumps between adjacent fields. ## Labels Labels should be: - Maximum three words, written in sentence case - No colon at the end - Never replaced by placeholders — placeholders disappear on input and are inaccessible Use the `required` prop to mark fields where the component supports it — do not add custom text. Mark only optional fields when most are required, or only required fields when most are optional. ## Hiding and disabling fields **Prefer disabled over hidden** for fields the user cannot access due to permissions. Hiding a field entirely gives no signal that the capability exists. Use `disabled` to show it exists but is unavailable, with a tooltip explaining why where possible. Use `readOnly` (not `disabled`) when a field already contains data that cannot be edited in the current context. **Progressive disclosure** is appropriate when a field is only relevant based on another selection. Hide the dependent field by default and reveal it only when the triggering condition is met — for example, showing a retry interval field only when automatic retries are enabled. ## Submit button behaviour Enable the submit button by default when a user is filling out a form for the first time. Disable it only: - While the form is submitting (to prevent double-submission) - When the user is editing an existing form and has made no changes yet - When permissions prevent the action (provide a tooltip explaining why) ❌ Don't disable submit buttons to enforce validation — show validation errors instead. ## Validation Validate on submission (server-side) as the primary method. Display errors inline using the `error` prop on each field. For errors not tied to a specific field, or when there are more than 3 errors, show a summary at the top of the form. Do not render validation messages as separate elements outside the field component's `error` prop. ## Slug and time span fields `Slug` and `TimeSpanSelector` are available in `@octopusdeploy/design-system-octopus-components` for these specific input types. Use them rather than building custom implementations.