dotCMS / dotCMS/core

Frontend: global form structure drift — 29 forms without .form, 58 labels overriding global typography, 21 required markers not using dotFieldRequired

Open
#37,357 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

dotCMS : Technical Debt Type : Refactoring
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Problem

The dotCMS form system is global CSS in core-web/apps/dotcms-ui/src/style.css, and every rule is descendant-scoped to .form:

.form                      { @apply w-full space-y-5; }
.form .field               { @apply flex flex-col gap-1; }
.form .field > label       { @apply text-sm font-medium; }
.form .form-checkbox,
.form .form-radio          { @apply flex flex-row items-center gap-2; }
.form .form-checkbox label,
.form .form-radio label    { @apply text-sm font-normal; }
.form .p-field-hint        { @apply text-sm text-gray-500; }
.form .p-field-error       { @apply text-sm text-red-500; }
.p-label-input-required::after { content: "*"; }  /* added by the dotFieldRequired directive */

Two consequences that are being violated across the app today:

  1. A <form> that omits class="form" loses the entire system — .field grouping, label typography, hint and error styling all stop applying. Those forms are then styled ad hoc, per component.
  2. Because .form .field > label already sets size and weight, a label carrying its own text-sm / font-semibold / text-gray-900 fights the global rule. This is why forms drift visually field by field across portlets.

docs/frontend/STYLING_STANDARDS.md documents Tailwind-first, PrimeNG theming, and tags vs chips — but says nothing about forms, so neither reviewers nor the automated PR reviewer ever caught this.

Measured drift (core-web/libs + core-web/apps, *.html)

Violation Count
<form> without class="form" (of 59 total forms) 29
<label> carrying typography classes (text-sm, font-medium, font-semibold, text-gray-*, text-surface-*, text-color) 58
Hand-written class="p-label-input-required" instead of the dotFieldRequired directive 13
Hardcoded <span ...>*</span> asterisks instead of the directive's ::after 8
Deprecated PrimeFlex p-field wrappers instead of .field 21

For reference: .field is used 163 times and dotFieldRequired 70 times, so the convention is well established — the above is drift against it, not an unadopted proposal.

By area
Area form w/o .form label w/ typography manual required class PrimeFlex p-field Total
libs/portlets/dot-experiments 7 16 1 1 25
apps/dotcms-ui 5 14 0 6 25
libs/edit-content 3 1 2 12 18
libs/new-block-editor 1 10 0 0 11
libs/ui 1 3 4 0 8
libs/portlets/dot-roles 0 6 0 0 6
libs/block-editor 4 0 1 0 5
libs/portlets/dot-locales 1 0 2 2 5
libs/portlets/dot-content-drive 0 4 0 0 4
libs/portlets/edit-ema 2 1 1 0 4
libs/portlets/dot-users 1 1 2 0 4
Remaining (dotcms-scss, dot-rules, dot-plugins, dot-tags, dotcdn) 5 2 0 0 7

Reference implementation

libs/portlets/dot-tags/src/lib/dot-tags-create/dot-tags-create.component.html — the whole form, with zero component SCSS:

<form class="form" [formGroup]="form" (ngSubmit)="onSubmit()">
    <div class="field">
        <label for="tagName" dotFieldRequired>{{ 'tags.form.tag-name' | dm }}</label>
        <input pInputText id="tagName" formControlName="name" class="w-full" />
    </div>
    <div class="field">
        <label for="tagSite">{{ 'tags.form.site' | dm }}</label>
        <dot-site id="tagSite" formControlName="siteId" />
    </div>
</form>

Acceptance criteria

  • AC1 — Document the rule. docs/frontend/STYLING_STANDARDS.md gains a Forms section stating: <form> must carry class="form"; each label + control is grouped in <div class="field">; checkbox/radio rows use .form-checkbox / .form-radio; labels carry no class attribute and are a direct child of .field; labels of required controls use the dotFieldRequired directive (with [checkIsRequiredControl] when the validator is dynamic); hints and errors use .p-field-hint / .p-field-error; no component SCSS for form layout.
  • AC2 — Every <form> carries class="form". The 29 offenders are migrated, and the hand-rolled layout classes on the form tag (space-y-*, flex flex-col gap-*, w-full) are removed in the same edit.
  • AC3 — Labels are clean. The 58 labels drop their typography classes. Non-typographic behavioral classes (e.g. cursor-pointer on a checkbox label) may stay. Any label not already a direct child of .field is unwrapped.
  • AC4 — Required markers come from the directive. The 13 hand-written p-label-input-required classes and 8 hardcoded * spans are replaced by dotFieldRequired on the label. No template references p-label-input-required directly.
  • AC5 — PrimeFlex removed from forms. The 21 p-field wrappers become .field (or .form-checkbox / .form-radio where the row is horizontal).
  • AC6 — No visual regression. Each migrated form is verified in the UI: field spacing (space-y-5), label size/weight, required asterisk, and hint/error text all render as before or better. Existing specs pass; specs asserting on removed classes are updated.
  • AC7 — Guard against re-drift. <form> without class="form" and labels with typography classes are caught automatically going forward (the dotcms-workflows PR reviewer already enforces this as of v3.3.0 — see note below; an ESLint/@angular-eslint template rule would make it hard-fail in CI).

Suggested sequencing

The areas are independent, so this can land as one PR per area rather than a single large one. Suggested order by ratio of impact to risk: libs/portlets/dot-roleslibs/portlets/dot-content-drivelibs/new-block-editorlibs/edit-contentapps/dotcms-uilibs/portlets/dot-experiments. libs/dotcms-scss/jsp/styleguide.html is a static styleguide page, not an Angular form — confirm whether it is in scope at all.

Related

The automated frontend PR reviewer now enforces these rules: dotCMS/dotcms-claude-plugins#33 (dotcms-workflows v3.3.0) adds a "Form Structure — Global Classes" checklist to dotcms-pr-code-reviewer, so new violations are flagged at review time. This issue covers the existing drift and AC1's missing documentation.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with docs/frontend/STYLING_STANDARDS.md and the reference implementation in libs/portlets/dot-tags/src/lib/dot-tags-create/dot-tags-create.component.html. Review the listed areas and migrate forms, labels, required markers, and p-field wrappers to the documented conventions, beginning with dot-roles and dot-content-drive. Done means all acceptance criteria are met, visual checks pass, and existing specs are updated as needed.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, tailwindcss
Domain
documentation, frontend
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.