field

Group labels, helper text, and errors with semantic field wrapper selectors.

Use the field wrapper and field parts to define standard form structure.

<div class="field">
  <label for="email">Email</label>
  <input id="email" type="email" placeholder="Email" />
  <p>Use your work email.</p>
</div>

<div class="field">
  <label for="invalid-email">Email</label>
  <input id="invalid-email" aria-invalid="true" />
  <p class="field-error">Enter a valid email.</p>
</div>

Example

View source
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AngularCSS Field</title>
    <link rel="stylesheet" href="../../css/preflight.css" />
    <link rel="stylesheet" href="../../css/angular.css" />
    <link rel="stylesheet" href="../example.css" />
    <script src="../../js/angular-ts.umd.js"></script>
    <script src="../../js/angular-css.umd.js"></script>
  </head>
  <body ng-app="angular.css" ng-cloak ng-init="name='Jane Doe'; email=''">
    <form class="stack">
      <fieldset class="field-set">
        <legend>Profile</legend>
        <div class="field-group">
          <div class="field">
            <label for="demo-profile-name">Name</label>
            <input
              id="demo-profile-name"
              aria-describedby="demo-profile-name-description"
              placeholder="Jane Doe"
              ng-model="name"
            />
            <p id="demo-profile-name-description">
              Use your public display name.
            </p>
          </div>
          <div class="field">
            <label for="demo-profile-email"> Email </label>
            <input
              id="demo-profile-email"
              type="email"
              placeholder="Enter an email"
              required
              aria-describedby="demo-profile-email-error"
              ng-model="email"
            />
            <p
              id="demo-profile-email-error"
              ng-show="!email"
              class="field-error"
            >
              Enter a valid email.
            </p>
          </div>
        </div>
      </fieldset>
      <output class="output">
        Preview: <span ng-bind="name"></span>
        <span ng-bind="email ? '(' + email + ')' : '(email required)'"></span>
      </output>
    </form>
  </body>
</html>

Workflows

View source
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AngularCSS Field Workflows</title>
    <link rel="stylesheet" href="../../css/preflight.css" />
    <link rel="stylesheet" href="../../css/angular.css" />
    <link rel="stylesheet" href="../example.css" />
    <script src="../../js/angular-ts.umd.js"></script>
    <script src="../../js/angular-css.umd.js"></script>
  </head>
  <body
    ng-app="angular.css"
    ng-cloak
    ng-init="fieldState={username:'',password:'',feedback:'',department:'',hardDisks:true,externalDisks:false,cds:false,servers:false,sync:true,twoFactor:false,plan:'monthly',environment:'kubernetes',minimum:200,maximum:800,street:'',city:'',zip:'',push:true,pushTasks:false,emailTasks:false,profileName:'',message:'Ready',sameAsShipping:true,month:'',year:''}"
  >
    <main class="field-workflow-grid" aria-label="Field workflows">
      <section data-example="field-input" class="field-workflow">
        <fieldset class="field-set">
          <div class="field-group">
            <div class="field">
              <label for="field-username">Username</label
              ><input
                id="field-username"
                ng-model="fieldState.username"
                placeholder="Max Leiter"
              />
              <p>Choose a unique username for your account.</p>
            </div>
            <div class="field">
              <label for="field-password">Password</label>
              <p>Must be at least 8 characters long.</p>
              <input
                id="field-password"
                type="password"
                ng-model="fieldState.password"
                placeholder="••••••••"
              />
            </div>
          </div>
        </fieldset>
      </section>

      <section data-example="field-textarea" class="field-workflow">
        <fieldset class="field-set">
          <div class="field-group">
            <div class="field">
              <label for="field-feedback">Feedback</label
              ><textarea
                id="field-feedback"
                ng-model="fieldState.feedback"
                placeholder="Your feedback helps us improve..."
                rows="4"
              ></textarea>
              <p>Share your thoughts about our service.</p>
            </div>
          </div>
        </fieldset>
      </section>

      <section data-example="field-select" class="field-workflow">
        <div class="field">
          <label for="field-department">Department</label>
          <select id="field-department" ng-model="fieldState.department">
            <option value="">Choose department</option>
            <option>Engineering</option>
            <option>Design</option>
            <option>Marketing</option>
            <option>Sales</option>
            <option>Customer Support</option>
          </select>
          <p>Select your department or area of work.</p>
        </div>
      </section>

      <section data-example="field-checkbox" class="field-workflow">
        <div class="field-group">
          <fieldset class="field-set">
            <legend variant="label">Show these items on the desktop</legend>
            <p>Select the items you want to show on the desktop.</p>
            <div class="field-choice-list checkbox-group">
              <div orientation="horizontal" class="field">
                <input
                  id="field-hard-disks"
                  type="checkbox"
                  ng-model="fieldState.hardDisks"
                /><label for="field-hard-disks">Hard disks</label>
              </div>
              <div orientation="horizontal" class="field">
                <input
                  id="field-external-disks"
                  type="checkbox"
                  ng-model="fieldState.externalDisks"
                /><label for="field-external-disks">External disks</label>
              </div>
              <div orientation="horizontal" class="field">
                <input
                  id="field-cds"
                  type="checkbox"
                  ng-model="fieldState.cds"
                /><label for="field-cds">CDs, DVDs, and iPods</label>
              </div>
              <div orientation="horizontal" class="field">
                <input
                  id="field-servers"
                  type="checkbox"
                  ng-model="fieldState.servers"
                /><label for="field-servers">Connected servers</label>
              </div>
            </div>
          </fieldset>
          <hr />
          <div orientation="horizontal" class="field">
            <input id="field-sync" type="checkbox" ng-model="fieldState.sync" />
            <section>
              <label for="field-sync"
                >Sync Desktop &amp; Documents folders</label
              >
              <p>Access these folders from your other devices.</p>
            </section>
          </div>
        </div>
      </section>

      <section data-example="field-switch" class="field-workflow">
        <div orientation="horizontal" class="field-switch-demo field">
          <label for="field-2fa">Multi-factor authentication</label
          ><input
            role="switch"
            id="field-2fa"
            type="checkbox"
            ng-model="fieldState.twoFactor"
          />
        </div>
      </section>

      <section data-example="field-radio" class="field-workflow">
        <fieldset class="field-set field-choice-list">
          <legend variant="label">Subscription Plan</legend>
          <p>Yearly and lifetime plans offer significant savings.</p>

          <div orientation="horizontal" class="field">
            <input
              id="field-monthly"
              name="field-plan"
              type="radio"
              value="monthly"
              ng-model="fieldState.plan"
            /><label for="field-monthly">Monthly ($9.99/month)</label>
          </div>
          <div orientation="horizontal" class="field">
            <input
              id="field-yearly"
              name="field-plan"
              type="radio"
              value="yearly"
              ng-model="fieldState.plan"
            /><label for="field-yearly">Yearly ($99.99/year)</label>
          </div>
          <div orientation="horizontal" class="field">
            <input
              id="field-lifetime"
              name="field-plan"
              type="radio"
              value="lifetime"
              ng-model="fieldState.plan"
            /><label for="field-lifetime">Lifetime ($299.99)</label>
          </div>
        </fieldset>
      </section>

      <section data-example="field-slider" class="field-workflow">
        <div class="field">
          <strong>Price Range</strong>
          <p>
            Set your budget range (${{ fieldState.minimum }} - ${{
            fieldState.maximum }}).
          </p>
          <div
            ng-range-slider
            min="0"
            max="1000"
            aria-label="Price Range"
            class="field-slider-demo"
          >
            <input
              type="range"
              min="0"
              max="1000"
              step="10"
              ng-model="fieldState.minimum"
              aria-label="Minimum budget"
            /><input
              type="range"
              min="0"
              max="1000"
              step="10"
              ng-model="fieldState.maximum"
              aria-label="Maximum budget"
            />
          </div>
        </div>
      </section>

      <section data-example="field-choice-card" class="field-workflow">
        <div class="field-group">
          <fieldset class="field-set field-card-list">
            <legend variant="label">Compute Environment</legend>
            <p>Select the compute environment for your cluster.</p>

            <label for="field-kubernetes"
              ><div orientation="horizontal" class="field">
                <section>
                  <strong>Kubernetes</strong>
                  <p>Run GPU workloads on a K8s cluster.</p>
                </section>
                <input
                  id="field-kubernetes"
                  name="environment"
                  type="radio"
                  value="kubernetes"
                  ng-model="fieldState.environment"
                /></div></label
            ><label for="field-vm"
              ><div orientation="horizontal" class="field">
                <section>
                  <strong>Virtual Machine</strong>
                  <p>Access a cluster to run GPU workloads.</p>
                </section>
                <input
                  id="field-vm"
                  name="environment"
                  type="radio"
                  value="vm"
                  ng-model="fieldState.environment"
                /></div
            ></label>
          </fieldset>
        </div>
      </section>

      <section data-example="field-fieldset" class="field-workflow">
        <fieldset class="field-set">
          <legend>Address Information</legend>
          <p>We need your address to deliver your order.</p>
          <div class="field-group">
            <div class="field">
              <label for="field-street">Street Address</label
              ><input
                id="field-street"
                ng-model="fieldState.street"
                placeholder="123 Main St"
              />
            </div>
            <div class="field-two-column">
              <div class="field">
                <label for="field-city">City</label
                ><input
                  id="field-city"
                  ng-model="fieldState.city"
                  placeholder="New York"
                />
              </div>
              <div class="field">
                <label for="field-zip">Postal Code</label
                ><input
                  id="field-zip"
                  ng-model="fieldState.zip"
                  placeholder="90502"
                />
              </div>
            </div>
          </div>
        </fieldset>
      </section>

      <section data-example="field-group" class="field-workflow">
        <div class="field-group">
          <fieldset class="field-set">
            <label>Responses</label>
            <p>
              Get notified when ChatGPT responds to requests that take time.
            </p>
            <div orientation="horizontal" class="field">
              <input
                id="field-push"
                type="checkbox"
                ng-model="fieldState.push"
                disabled
              /><label for="field-push">Push notifications</label>
            </div>
          </fieldset>
          <hr />
          <fieldset class="field-set">
            <label>Tasks</label>
            <p>
              Get notified when tasks have updates.
              <a href="#tasks">Manage tasks</a>
            </p>
            <div class="field-choice-list">
              <div orientation="horizontal" class="field">
                <input
                  id="field-push-tasks"
                  type="checkbox"
                  ng-model="fieldState.pushTasks"
                /><label for="field-push-tasks">Push notifications</label>
              </div>
              <div orientation="horizontal" class="field">
                <input
                  id="field-email-tasks"
                  type="checkbox"
                  ng-model="fieldState.emailTasks"
                /><label for="field-email-tasks">Email notifications</label>
              </div>
            </div>
          </fieldset>
        </div>
      </section>

      <section
        data-example="field-responsive"
        class="field-workflow field-workflow-wide"
      >
        <form
          ng-submit="fieldState.message='Profile submitted '+fieldState.profileName"
        >
          <fieldset class="field-set">
            <legend>Profile</legend>
            <p>Fill in your profile information.</p>
            <div class="field-group">
              <div orientation="responsive" class="field">
                <section>
                  <label for="field-profile-name">Name</label>
                  <p>Provide your full name for identification</p>
                </section>
                <input
                  id="field-profile-name"
                  ng-model="fieldState.profileName"
                  placeholder="Evil Rabbit"
                  required
                />
              </div>
              <div orientation="responsive" class="field-form-actions field">
                <button type="submit">Submit</button
                ><button
                  type="button"
                  variant="outline"
                  ng-click="fieldState.message='Cancelled'"
                >
                  Cancel
                </button>
              </div>
            </div>
          </fieldset>
        </form>
      </section>

      <section
        data-example="field-demo"
        class="field-workflow field-workflow-wide"
      >
        <form ng-submit="fieldState.message='Payment submitted'">
          <div class="field-group">
            <fieldset class="field-set">
              <legend>Payment Method</legend>
              <p>All transactions are secure and encrypted</p>
              <div class="field-group">
                <div class="field">
                  <label for="field-card-name">Name on Card</label
                  ><input
                    id="field-card-name"
                    placeholder="Evil Rabbit"
                    required
                  />
                </div>
                <div class="field">
                  <label for="field-card-number">Card Number</label
                  ><input
                    id="field-card-number"
                    placeholder="1234 5678 9012 3456"
                    required
                  />
                  <p>Enter your 16-digit card number</p>
                </div>
                <div class="field-three-column">
                  <div class="field">
                    <label for="field-month">Month</label
                    ><input id="field-month" placeholder="MM" />
                  </div>
                  <div class="field">
                    <label for="field-year">Year</label
                    ><input id="field-year" placeholder="YYYY" />
                  </div>
                  <div class="field">
                    <label for="field-cvv">CVV</label
                    ><input id="field-cvv" placeholder="123" required />
                  </div>
                </div>
              </div>
            </fieldset>
            <hr />
            <fieldset class="field-set">
              <legend>Billing Address</legend>
              <p>The billing address associated with your payment method</p>
              <div orientation="horizontal" class="field">
                <input
                  id="field-same-shipping"
                  type="checkbox"
                  ng-model="fieldState.sameAsShipping"
                /><label for="field-same-shipping"
                  >Same as shipping address</label
                >
              </div>
            </fieldset>
            <fieldset class="field-set">
              <div class="field">
                <label for="field-comments">Comments</label
                ><textarea
                  id="field-comments"
                  placeholder="Add any additional comments"
                ></textarea>
              </div>
            </fieldset>
            <div orientation="horizontal" class="field-form-actions field">
              <button type="submit">Submit</button
              ><button type="button" variant="outline">Cancel</button>
            </div>
          </div>
        </form>
      </section>

      <section
        data-example="field-rtl"
        class="field-workflow field-workflow-wide"
        dir="rtl"
        lang="ar"
      >
        <form>
          <div class="field-group">
            <fieldset class="field-set">
              <legend>طريقة الدفع</legend>
              <p>جميع المعاملات آمنة ومشفرة</p>
              <div class="field-group">
                <div class="field">
                  <label for="field-card-name-rtl">الاسم على البطاقة</label
                  ><input id="field-card-name-rtl" placeholder="Evil Rabbit" />
                </div>
                <div class="field">
                  <label for="field-card-number-rtl">رقم البطاقة</label
                  ><input
                    id="field-card-number-rtl"
                    placeholder="1234 5678 9012 3456"
                  />
                  <p>أدخل رقم البطاقة المكون من 16 رقمًا</p>
                </div>
                <div class="field-three-column">
                  <div class="field">
                    <label>الشهر</label><input placeholder="ش.ش" />
                  </div>
                  <div class="field">
                    <label>السنة</label><input placeholder="YYYY" />
                  </div>
                  <div class="field">
                    <label>CVV</label><input placeholder="123" />
                  </div>
                </div>
              </div>
            </fieldset>
            <hr />
            <div orientation="horizontal" class="field">
              <input
                id="field-same-shipping-rtl"
                type="checkbox"
                checked
              /><label for="field-same-shipping-rtl">نفس عنوان الشحن</label>
            </div>
            <div class="field">
              <label for="field-comments-rtl">تعليقات</label
              ><textarea
                id="field-comments-rtl"
                placeholder="أضف أي تعليقات إضافية"
              ></textarea>
            </div>
            <div orientation="horizontal" class="field-form-actions field">
              <button type="button">إرسال</button
              ><button type="button" variant="outline">إلغاء</button>
            </div>
          </div>
        </form>
      </section>
      <output class="field-workflow-output"> {{ fieldState.message }} </output>
    </main>
  </body>
</html>

Validation States

Fields derive presentation from native validity and aria-invalid; AngularTS structural directives may insert or remove controls and descriptions.

View source
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AngularCSS Field State Workflows</title>
    <link rel="stylesheet" href="../../css/preflight.css" />
    <link rel="stylesheet" href="../../css/angular.css" />
    <link rel="stylesheet" href="../example.css" />
    <script src="../../js/angular-ts.umd.js"></script>
    <script src="../../js/angular-css.umd.js"></script>
  </head>
  <body
    ng-app="angular.css"
    ng-cloak
    ng-init="state={requiredEmail:'',dynamicVisible:false}"
  >
    <form class="component-state-grid" aria-label="Field state contracts">
      <section
        class="component-state-section"
        aria-labelledby="field-messages-title"
      >
        <h2 id="field-messages-title">Messages</h2>
        <div id="message-field" class="field">
          <label for="message-control">Name</label>
          <input
            id="message-control"
            aria-describedby="message-description message-error"
          />
          <p id="message-description">Use your public display name.</p>
          <p id="message-error" class="field-error">
            The display name is already in use.
          </p>
        </div>
      </section>

      <section
        class="component-state-section"
        aria-labelledby="field-invalid-title"
      >
        <h2 id="field-invalid-title">Invalid state</h2>
        <div id="explicit-invalid-field" class="field">
          <label for="explicit-invalid-control"> Workspace </label>
          <input id="explicit-invalid-control" aria-invalid="true" />
        </div>
      </section>

      <section
        class="component-state-section"
        aria-labelledby="field-required-title"
      >
        <h2 id="field-required-title">Native validation</h2>
        <div id="required-field" class="field">
          <label for="required-email">Email</label>
          <input
            id="required-email"
            type="email"
            required
            ng-model="state.requiredEmail"
          />
        </div>
      </section>

      <section
        class="component-state-section"
        aria-labelledby="field-dynamic-title"
      >
        <h2 id="field-dynamic-title">Conditional control</h2>
        <div id="dynamic-field" class="field">
          <label for="dynamic-email">Team email</label>
          <p id="dynamic-email-description">Use the address for your team.</p>
          <input
            ng-if="state.dynamicVisible"
            id="dynamic-email"
            type="email"
            aria-describedby="dynamic-email-description"
            required
          />
        </div>
        <button
          variant="outline"
          type="button"
          ng-click="state.dynamicVisible=true"
          ng-disabled="state.dynamicVisible"
        >
          Add email field
        </button>
      </section>
    </form>
  </body>
</html>

Installation

Load the AngularCSS stylesheet. This entry needs no AngularCSS JavaScript or angular.css module dependency. Add AngularTS when using application bindings such as ng-model or ng-click. See Installation for the complete setup.

This entry uses native HTML and CSS. AngularCSS registers no runtime directive for it. Native labels, descriptions, and validation.

Anatomy

Root styling selector

  • .field

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
orientationAuthoredField layout: horizontal or responsive; omit for the vertical layout.
variantAuthoredCompact label typography when authored on a fieldset legend.

Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.

CSS custom properties

This styling hook does not define component-specific CSS custom properties.

DOM events

This component does not emit a component-specific custom event.

Native DOM events continue to work normally. AngularTS event directives such as ng-click and ng-keydown, plus the data-change model callback, remain application-owned.

Behavior

Field is a styling-only semantic form composition. Native labels, validation, and aria-describedby own relationships; AngularTS forms and structural directives own model, error visibility, and submission state.

AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.

Accessibility

Connect every control to a native label. Give descriptions and errors stable IDs and author aria-describedby on the control. Use native fieldset and legend only for actual groups of related controls.

Authored accessible names and relationships are preserved. Test the final composition with keyboard navigation and assistive technology because labels and content come from the application.

Customization

Target semantic elements, native state selectors, and component classes with ordinary CSS. Behavior and accessible state remain with native HTML and AngularTS; visual choices belong in the application stylesheet.

Read Customization for layer order, design tokens, state variants, and iframe demo isolation.