Skip to content

Form Fields

Forms are a core part of most web applications and require a solid, predictable HTML structure to be maintainable and scalable. Beyond visual styling, forms rely heavily on semantic markup to ensure proper validation, accessibility, and JavaScript behavior.

Every form field should:

  • Be wrapped in a dedicated container (form group)
  • Include a label properly associated with its input
  • Expose a predictable DOM structure for styling and JS hooks
  • Reserve space for validation and error messages

Keeping this structure consistent across all input types (text, select, checkbox, radio, etc.) allows us to reuse styles, validation logic, and interaction patterns across projects, reducing complexity and preventing edge cases.


  • Form Group -> only has margin bottom, and the role is to separate between fields
  • Form Label -> Displays informational text for input (not mandatory)
  • Form field -> can be input type text, checkbox, select,radio,etc, they have colors for sucess & error
  • Form Error -> Is only visible & generated via JS, they are usefull when a form field (custom) needs to display custom error messages
[ Form Group ]
[ Label ] Label Name [ Label ]
[ Input/Select/Radio ] Label Name [ /Input/Select/Radio ]
[ Error ] Error Message [ /Error ]
[/Form Group]

The layout can be adjusted freely, as long as the column system is respected in all cases and existing inline lists are preserved where applicable.

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; border: 1px solid #ccc; border-radius: 8px;">
<iframe
src="https://codepen.io/andresclua/full/yyYQjyR"
style="position: absolute; top:0; left:0; width:100%; height:100%; border:0;"
allowfullscreen
loading="lazy">
</iframe>
</div>

The c--spinner component will now be part of all our projects. It provides a consistent way to indicate to users that an action is in progress, such as:

  • A search is running
  • A page transition is loading
  • A form is being submitted

In the next example you are going to see spinner in action

<iframe
src="https://codepen.io/andresclua/embed/MYazBOV?default-tab=result"
style="width: 100%; height: 500px;"
frameborder="0"
loading="lazy"
allowfullscreen>
</iframe>

From now on this is the structure that we want to implement, since we can take advantage of a shared and predictable DOM structure, reusable styles, and unified JavaScript logic across all projects. This approach reduces edge cases, simplifies maintenance, and ensures a consistent user experience.


All form fields must support the following states:

  • Default – Neutral, ready for interaction
  • Focus – Clearly visible focus state for accessibility
  • Success – Used when validation passes
  • Error – Used when validation fails and paired with a Form Error message
  • Disabled – Non-interactive, visually distinct

State changes should be handled via classes and not inline styles.


Simple Form Validation


  • Validation should be triggered on submit and, when needed, on blur.
  • Error messages must be specific and helpful.
  • Errors should never rely on color alone — text feedback is mandatory.
  • Native browser validation can be overridden if custom behavior is required.
  • Every input must be associated with a label (visually hidden labels are acceptable).
  • Use semantic HTML whenever possible.
  • Ensure sufficient color contrast in all states.
  • Error messages must be announced to screen readers when they appear.

Knowledge Check

Test your understanding of this section

Loading questions...