Skip to main content

Lunar Fusion

Text Field and Text Area

Adobe Spectrum CSS Token Migration

Textfield contained several new child elements which needed to reflect design specifications for their layout. I also needed to add a layout variant for side label and resolve how the other child elements would behave for this variant.

Text area had a unique feature: automatic height. This is not a normal feature of text area, so some research needed to be done.


Related Links

Adobe Spectrum textfield variants

Textfield Challenges

Child Elements

Text field had several child elements to consider.

  1. Label
  2. Character Count
  3. Help Text
  4. Validation Marker
text field

Character count (new child element).

text field

Help Text

Side Label

Additionally, a layout variant with side label needed to be provided.

No design specs were provided to specify how all child elements would behave with the side label variant. I created a diagram to share with the Adobe designers and ensure the elements aligned as intended for each layout. They chose option 2 with the help text aligned with the input rather than with the side label.

As a designer, I imagined this would be their choice. But it's always better to clarify than to assume.

text field

Side label variant demo for design

CSS Grid

I used CSS grid to build the layouts, which provided minute control of where each child element would be placed in each layout variant. Auto sizing was used so as to avoid interfering with the specific content needs of each application. I used inline-grid so as to avoid forcing block behavior on the fields, which may occur inline as well.

Using grid also allowed me to place the focus indicator within the same grid area as the text field, aligned to spec and without disrupting the other child elements.

                .spectrum-Textfield {
                  /* Grid layout for child components */
                  display: inline-grid;
                  grid-template-columns: auto auto;
                  grid-template-rows: auto auto auto;
                }
text field

My CSS grid diagram

Flexible Text Area Height

Text area components normally have a set height with the option to provide a resizing handle for the user. Adobe's designers had a unique requirement: unless the height or a text area was specified, it should grow to accommodate the content as the user enters it.

The technique I investigated involved adding some markup to the textfield. Adding onInput="this.parentNode.dataset.replicatedValue = this.value" to the HTML of the text area field markup created a piece of data that could be replicated in a psuedo element, as seen below.

                /* sizer which allows auto height of input */
                &::before {
                  content: attr(data-replicated-value) " ";
                  white-space: pre-wrap;
                  inline-size: 100%;
                  block-size: auto;
                  visibility: hidden;
                  pointer-events: none;
                  /* place in same cell as input */
                  grid-row: 2;
                  grid-column: 1 / span 2;
                }

When placed into the same grid area as the field, the psuedo element forces the field to respond to the height of the data as it is entered.

Although this additional functionality was deemed out of scope for the work, the CSS is set up to allow it to be added by individual product teams. The following was included in the text field CSS.

                /* place in same cell: input, focus indicator, and grows sizer */
                grid-row: 2;
                grid-column: 1 / span 2;
text field

Adobe design text area dynamic height specs

Textfield CSS

Archived from 2022

  /*
  Copyright 2022 Adobe. All rights reserved.
  This file is licensed to you under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License. You may obtain a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software distributed under
  the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
  OF ANY KIND, either express or implied. See the License for the specific language
  governing permissions and limitations under the License.
  */
   
  .spectrum-Textfield {
    --spectrum-texfield-animation-duration: var(--spectrum-animation-duration-100);
   
    --spectrum-textfield-width: 240px; /* override per api */
    --spectrum-textfield-min-width: var(--spectrum-text-field-minimum-width-multiplier);
    --spectrum-textfield-corner-radius: var(--spectrum-corner-radius-100);
   
    /* default height */
    --spectrum-textfield-height: var(--spectrum-component-height-100);
   
    /* default spacing */
    --spectrum-textfield-spacing-inline: var(--spectrum-component-edge-to-text-100);
    --spectrum-textfield-spacing-inline-quiet: var(--spectrum-field-edge-to-text-quiet);
    --spectrum-textfield-spacing-block-start: var(--spectrum-component-top-to-text-100);
    --spectrum-textfield-spacing-block-end: var(--spectrum-component-bottom-to-text-100);
    --spectrum-textfield-spacing-block-quiet: var(--spectrum-field-edge-to-border-quiet);
   
    /* default label spacing */
    --spectrum-textfield-label-spacing-block: var(--spectrum-field-label-to-component);
    --spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-medium);
    --spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-100);
   
    /* default help text spacing */
    --spectrum-textfield-helptext-spacing-block: var(--spectrum-help-text-to-component);
   
    /* default icon size */
    --spectrum-textfield-icon-size-invalid: var(--spectrum-workflow-icon-size-100);
   
    /* default icon spacing */
    --spectrum-textfield-icon-spacing-inline-start-invalid: var(--spectrum-field-text-to-alert-icon-medium);
    --spectrum-textfield-icon-spacing-inline-end-invalid: var(--spectrum-field-edge-to-alert-icon-medium);
    --spectrum-textfield-icon-spacing-inline-end-quiet-invalid: var(--spectrum-field-edge-to-alert-icon-quiet);
    --spectrum-textfield-icon-spacing-block-invalid: var(--spectrum-field-top-to-alert-icon-medium);
   
    --spectrum-textfield-icon-spacing-inline-start-valid:var(--spectrum-field-text-to-validation-icon-medium);
    --spectrum-textfield-icon-spacing-inline-end-valid: var(--spectrum-field-edge-to-validation-icon-medium);
    --spectrum-textfield-icon-spacing-inline-end-quiet-valid: var(--spectrum-field-edge-to-validation-icon-quiet);
    --spectrum-textfield-icon-spacing-block-valid: var(--spectrum-field-top-to-validation-icon-medium);
   
    /* icon end spacing override for combobox */
    --spectrum-textfield-icon-spacing-inline-end-override: 32px; /* TODO - placeholder - reevaluate after combobox migration */
   
   
    /* TODO - icon spacing override for search - reevaluate after search is migrated */
    --spectrum-Textfield-workflow-icon-width: 18px;
    --spectrum-Textfield-workflow-icon-gap: 6px;
   
   
    /* font styles */
    --spectrum-textfield-font-family: var(--spectrum-sans-font-family-stack);
    --spectrum-textfield-font-weight: var(--spectrum-regular-font-weight);
    --spectrum-textfield-placeholder-font-size: var(--spectrum-font-size-100);
   
    /* character count */
    --spectrum-textfield-character-count-font-family: var(--spectrum-sans-font-family-stack);
    --spectrum-textfield-character-count-font-weight: var(--spectrum-regular-font-weight);
    --spectrum-textfield-character-count-font-size: var(--spectrum-font-size-75);
    --spectrum-textfield-character-count-spacing-inline: var(--spectrum-spacing-200);
    --spectrum-textfield-character-count-spacing-block: var(--spectrum-component-bottom-to-text-75);
    --spectrum-textfield-character-count-spacing-inline-side: var(--spectrum-side-label-character-count-to-field);
    --spectrum-textfield-character-count-spacing-block-side: var(--spectrum-side-label-character-count-top-margin-medium);
   
    /* focus indicator */
    --spectrum-textfield-focus-indicator-width: var(--spectrum-focus-indicator-thickness);
    --spectrum-textfield-focus-indicator-gap: var(--spectrum-focus-indicator-gap);
   
    /*** Colors ***/
    --spectrum-textfield-background-color: var(--spectrum-gray-50);
   
    /* Text Colors */
    --spectrum-textfield-text-color-default: var(--spectrum-neutral-content-color-default);
    --spectrum-textfield-text-color-hover: var(--spectrum-neutral-content-color-hover);
    --spectrum-textfield-text-color-focus: var(--spectrum-neutral-content-color-focus);
    --spectrum-textfield-text-color-focus-hover: var(-spectrum-neutral-content-color-focus-hover);
    --spectrum-textfield-text-color-keyboard-focus: var(--spectrum-neutral-content-color-key-focus);
   
    /* Read Only Text Color */
    --spectrum-textfield-text-color-readonly: var(--spectrum-neutral-content-color-default);
   
    /* Disabled Colors */
    --spectrum-textfield-background-color-disabled: var(--spectrum-disabled-background-color);
    --spectrum-textfield-border-color-disabled: var(--spectrum-disabled-border-color);
    --spectrum-textfield-text-color-disabled: var(--spectrum-disabled-content-color);
   
    /* Invalid Colors */
    --spectrum-textfield-border-color-invalid-default: var(--spectrum-negative-border-color-default);
    --spectrum-textfield-border-color-invalid-hover: var(--spectrum-negative-border-color-hover);
    --spectrum-textfield-border-color-invalid-focus: var(--spectrum-negative-border-color-focus);
    --spectrum-textfield-border-color-invalid-focus-hover: var(--spectrum-negative-border-color-focus-hover);
    --spectrum-textfield-border-color-invalid-keyboard-focus: var(--spectrum-negative-border-color-key-focus);
    --spectrum-textfield-icon-color-invalid: var(--spectrum-negative-visual-color);
   
    --spectrum-textfield-text-color-invalid: var(--spectrum-neutral-content-color-default);
   
     /* Valid Colors */
    --spectrum-textfield-text-color-valid: var(--spectrum-neutral-content-color-default);
    --spectrum-textfield-icon-color-valid: var(--spectrum-positive-visual-color);
   
     /* Focus Indicator Color */
    --spectrum-textfield-focus-indicator-color: var(--spectrum-focus-indicator-color);
   
    /* Text Area / Multiline */
    --spectrum-text-area-min-inline-size: var(--spectrum-text-area-minimum-width);
    --spectrum-text-area-min-block-size: var(--spectrum-text-area-minimum-height);
    --spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-100);
  }
   
  /********* Text field t-shirt sizes *********/
  .spectrum-Textfield--sizeS {
    --spectrum-textfield-height: var(--spectrum-component-height-75);
    --spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-small);
    --spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-100);
    --spectrum-textfield-placeholder-font-size: var(--spectrum-font-size-75);
    --spectrum-textfield-spacing-inline: var(--spectrum-component-edge-to-text-75);
    --spectrum-textfield-icon-size-invalid: var(--spectrum-workflow-icon-size-75);
    --spectrum-textfield-icon-spacing-inline-end-invalid: var(--spectrum-field-edge-to-alert-icon-small);
    --spectrum-textfield-icon-spacing-inline-end-valid: var(--spectrum-field-edge-to-validation-icon-small);
    --spectrum-textfield-icon-spacing-block-invalid: var(--spectrum-field-top-to-alert-icon-small);
    --spectrum-textfield-icon-spacing-block-valid: var(--spectrum-field-top-to-validation-icon-small);
    --spectrum-textfield-icon-spacing-inline-start-invalid: var(--spectrum-field-text-to-alert-icon-small);
    --spectrum-textfield-icon-spacing-inline-start-valid: var(--spectrum-field-text-to-validation-icon-small);
    --spectrum-textfield-character-count-font-size: var(--spectrum-font-size-75);
    --spectrum-textfield-character-count-spacing-block: var(--spectrum-component-bottom-to-text-75);
    --spectrum-textfield-character-count-spacing-block-quiet: var(--spectrum-character-count-to-field-quiet-small);
    --spectrum-textfield-character-count-spacing-block-side: var(--spectrum-side-label-character-count-top-margin-small);
   
    /* Text Area / Multiline size small */
    --spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-75);
  }
   
  .spectrum-Textfield--sizeM {
    --spectrum-textfield-height: var(--spectrum-component-height-100);
    --spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-medium);
    --spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-200);
    --spectrum-textfield-placeholder-font-size: var(--spectrum-font-size-100);
    --spectrum-textfield-spacing-inline: var(--spectrum-component-edge-to-text-100);
    --spectrum-textfield-icon-size-invalid: var(--spectrum-workflow-icon-size-100);
    --spectrum-textfield-icon-spacing-inline-end-invalid: var(--spectrum-field-edge-to-alert-icon-medium);
    --spectrum-textfield-icon-spacing-inline-end-valid: var(--spectrum-field-edge-to-validation-icon-medium);
    --spectrum-textfield-icon-spacing-block-invalid: var(--spectrum-field-top-to-alert-icon-medium);
    --spectrum-textfield-icon-spacing-block-valid: var(--spectrum-field-top-to-validation-icon-medium);
    --spectrum-textfield-icon-spacing-inline-start-invalid: var(--spectrum-field-text-to-alert-icon-medium);
    --spectrum-textfield-icon-spacing-inline-start-valid:var(--spectrum-field-text-to-validation-icon-medium);
    --spectrum-textfield-character-count-font-size: var(--spectrum-font-size-75);
    --spectrum-textfield-character-count-spacing-block: var(--spectrum-component-bottom-to-text-75);
    --spectrum-textfield-character-count-spacing-block-quiet: var(--spectrum-character-count-to-field-quiet-medium);
    --spectrum-textfield-character-count-spacing-block-side: var(--spectrum-side-label-character-count-top-margin-medium);
   
    /* Text Area / Multiline size medium */
    --spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-100);
  }
   
  .spectrum-Textfield--sizeL {
    --spectrum-textfield-height: var(--spectrum-component-height-200);
    --spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-large);
    --spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-200);
    --spectrum-textfield-placeholder-font-size: var(--spectrum-font-size-200);
    --spectrum-textfield-spacing-inline: var(--spectrum-component-edge-to-text-200);
    --spectrum-textfield-icon-size-invalid: var(--spectrum-workflow-icon-size-200);
    --spectrum-textfield-icon-spacing-inline-end-invalid: var(--spectrum-field-edge-to-alert-icon-large);
    --spectrum-textfield-icon-spacing-inline-end-valid: var(--spectrum-field-edge-to-validation-icon-large);
    --spectrum-textfield-icon-spacing-block-invalid: var(--spectrum-field-top-to-alert-icon-large);
    --spectrum-textfield-icon-spacing-block-valid: var(--spectrum-field-top-to-validation-icon-large);
    --spectrum-textfield-icon-spacing-inline-start-invalid: var(--spectrum-field-text-to-alert-icon-large);
    --spectrum-textfield-icon-spacing-inline-start-valid:var(--spectrum-field-text-to-validation-icon-large);
    --spectrum-textfield-character-count-font-size: var(--spectrum-font-size-100);
    --spectrum-textfield-character-count-spacing-block: var(--spectrum-component-bottom-to-text-100);
    --spectrum-textfield-character-count-spacing-block-quiet: var(--spectrum-character-count-to-field-quiet-large);
    --spectrum-textfield-character-count-spacing-block-side: var(--spectrum-side-label-character-count-top-margin-large);
   
    /* Text Area / Multiline size large */
    --spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-200);
  }
   
  .spectrum-Textfield--sizeXL {
    --spectrum-textfield-height: var(--spectrum-component-height-300);
    --spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-extra-large);
    --spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-200);
    --spectrum-textfield-placeholder-font-size: var(--spectrum-font-size-300);
    --spectrum-textfield-spacing-inline: var(--spectrum-component-edge-to-text-200);
    --spectrum-textfield-icon-size-invalid: var(--spectrum-workflow-icon-size-300);
    --spectrum-textfield-icon-spacing-inline-end-invalid: var(--spectrum-field-edge-to-alert-icon-extra-large);
    --spectrum-textfield-icon-spacing-inline-end-valid: var(--spectrum-field-edge-to-validation-icon-extra-large);
    --spectrum-textfield-icon-spacing-block-invalid: var(--spectrum-field-top-to-alert-icon-extra-large);
    --spectrum-textfield-icon-spacing-block-valid: var(--spectrum-field-top-to-validation-icon-extra-large);
    --spectrum-textfield-icon-spacing-inline-start-invalid: var(--spectrum-field-text-to-alert-icon-extra-large);
    --spectrum-textfield-icon-spacing-inline-start-valid:var(--spectrum-field-text-to-validation-icon-extra-large);
    --spectrum-textfield-character-count-font-size: var(--spectrum-font-size-200);
    --spectrum-textfield-character-count-spacing-block: var(--spectrum-component-bottom-to-text-200);
    --spectrum-textfield-character-count-spacing-block-quiet: var(--spectrum-character-count-to-field-quiet-extra-large);
    --spectrum-textfield-character-count-spacing-block-side: var(--spectrum-side-label-character-count-top-margin-extra-large);
   
    /* Text Area / Multiline size extra large */
    --spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-300);
  }
   
  /********* WHCM *********/
  @media (forced-colors: active) {
    .spectrum-Textfield {
      --highcontrast-textfield-border-color-hover: Highlight;
      --highcontrast-textfield-border-color-focus: Highlight;
      --highcontrast-textfield-border-color-keyboard-focus: Highlight;
      --highcontrast-textfield-focus-indicator-color: CanvasText;
   
      --highcontrast-textfield-border-color-invalid-default: Highlight;
      --highcontrast-textfield-border-color-invalid-hover: Highlight;
      --highcontrast-textfield-border-color-invalid-focus: Highlight;
      --highcontrast-textfield-border-color-invalid-keyboard-focus: Highlight;
   
      --highcontrast-textfield-text-color-valid: CanvasText;
      --highcontrast-textfield-text-color-invalid: CanvasText;
   
      .spectrum-Textfield-input {
        --highcontrast-textfield-text-color-default: CanvasText;
        --highcontrast-textfield-text-color-hover: CanvasText;
        --highcontrast-textfield-text-color-keyboard-focus: CanvasText;
        --highcontrast-textfield-text-color-disabled: GrayText;
        --highcontrast-textfield-text-color-readonly: CanvasText;
   
        &::placeholder {
          --highcontrast-textfield-text-color-default: GrayText;
          --highcontrast-textfield-text-color-hover: GrayText;
          --highcontrast-textfield-text-color-keyboard-focus: GrayText;
          --highcontrast-textfield-text-color-disabled: GrayText;
          --highcontrast-textfield-text-color-readonly: CanvasText;
        }
      }
   
   
      &.is-focused,
      &.is-keyboardFocused {
        /* focus indicator is focused state */
        &::after {
          forced-color-adjust: none;
        }
      }
    }
  }
   
  /********* TEXT FIELD and TEXT AREA Outer Wrapper *********/
  .spectrum-Textfield {
    position: relative;
    outline: none;
    margin: auto;
   
    /* prevent input from expanding to width of helptext */
    inline-size: var(--mod-textfield-width, var(--spectrum-textfield-width));
   
    /*** ↓ Browser Mitigations for Text Field ↓ ***/
    /* Edge - Use padding instead of text-indent because text-indent does not left align the text  */
    text-indent: 0;
   
    /* Edge - Show the overflow for input. */
    overflow: visible;
   
    /* Firefox and Safari - Remove the margin for input. */
    margin: 0;
   
    /* Firefox -
      Removes the native spin buttons in Firefox; -moz-appearance: none results in spinners.
      This has to come after -webkit-appearance or it gets overridden (#214)
      Details: http://stackoverflow.com/questions/23372903/hide-spinner-in-input-number-firefox-29
   
      Sets the opacity to 1 as normalize.css sets an opacity to placeholders
      Details: https://github.com/csstools/normalize.css/blob/main/normalize.css#L297
    */
    -moz-appearance: textfield;
   
    /* All browsers - Change the input font styles */
    text-overflow: ellipsis;
   
    /* Grid layout for child components */
    display: inline-grid;
    grid-template-columns: auto auto;
    grid-template-rows: auto auto auto;
   
    /*** Focus Indicator - Unfocused Base Styles ***/
    &::after {
      block-size: calc(100% + (var(--mod-textfield-focus-indicator-gap, var(--spectrum-textfield-focus-indicator-gap)) * 2));
      inline-size: calc(100% + (var(--mod-textfield-focus-indicator-gap, var(--spectrum-textfield-focus-indicator-gap)) * 2));
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      margin-block-start: calc((var(--mod-textfield-focus-indicator-gap, var(--spectrum-textfield-focus-indicator-gap))
                                + var(--mod-textfield-focus-indicator-width, var(--spectrum-textfield-focus-indicator-width)))
                                * -1);
      margin-inline-start: calc((var(--mod-textfield-focus-indicator-gap, var(--spectrum-textfield-focus-indicator-gap))
                                + var(--mod-textfield-focus-indicator-width, var(--spectrum-textfield-focus-indicator-width)))
                                * -1);
      pointer-events: none;
      content: '';
      border-style: solid;
      border-color: transparent;
      border-width: 0;
      border-radius: calc(var(--mod-textfield-corner-radius, var(--spectrum-textfield-corner-radius))
                          + var(--mod-textfield-border-width, var(--spectrum-textfield-border-width))
                          + var(--mod-textfield-focus-indicator-gap, var(--spectrum-textfield-focus-indicator-gap)));
   
      /* place in same cell: input, focus indicator, and grows sizer */
      grid-row: 2 / span 1;
      grid-column: 1 / span 2;
    }
   
    &.is-keyboardFocused {
      /* focus indicator is focused state */
      &::after {
        border-color: var(--highcontrast-textfield-focus-indicator-color, var(--mod-textfield-focus-indicator-color, var(--spectrum-textfield-focus-indicator-color)));
        border-width: var(--mod-textfield-focus-indicator-width, var(--spectrum-textfield-focus-indicator-width));
      }
    }
   
    .is-readOnly & {
      &::after {
        border: 0;
      }
    }
   
    &--quiet {
      &::after {
        inline-size: 100%;
        block-size: calc(100% + var(--mod-textfield-focus-indicator-gap, var(--spectrum-textfield-focus-indicator-gap)));
        margin-inline-start: 0;
        margin-block-start: 0;
        border-radius: 0;
        border-color: var(--highcontrast-textfield-focus-indicator-color, var(--mod-textfield-focus-indicator-color, var(--spectrum-textfield-focus-indicator-color)));
      }
    }
   
    &--quiet.is-keyboardFocused {
      &::after {
        border-width: 0 0 var(--mod-textfield-focus-indicator-width, var(--spectrum-textfield-focus-indicator-width)) 0;
      }
    }
   
    /* TODO - reevaluate icon styles when search field is migrated */
    /* align search icon */
    .spectrum-Textfield-icon {
      display: block;
      position: absolute;
      top: 0;
      bottom: 0;
      margin-block: auto;
   
      color: var(--highcontrast-textfield-text-color-default, var(--mod-textfield-text-color-default, var(--spectrum-textfield-text-color-default)));
   
      .spectrum-Textfield.is-disabled & {
        color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-textfield-text-color-disabled)));
      }
   
      .spectrum-Textfield--quiet & {
        color: var(--highcontrast-textfield-text-color-default, var(--mod-textfield-text-color-default, var(--spectrum-textfield-text-color-default)));
      }
   
      .spectrum-Textfield--quiet.is-disabled & {
        color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-textfield-text-color-disabled)));
      }
   
      .spectrum-Textfield.is-readOnly & {
        color: var(--highcontrast-textfield-text-color-readonly, var(--mod-textfield-text-color-readonly, var(--spectrum-textfield-text-color-readonly)));
      }
    }
  }
   
  /********* Child Element - Validation Icons - ⚠️ ✅ *********/
  .spectrum-Textfield-validationIcon {
    /* specify validation class or web components will apply this to all icons */
    .spectrum-Textfield.is-valid &,
    .spectrum-Textfield.is-invalid & {
      position: absolute;
      pointer-events: all;
      top: 0;
      margin-inline-start: auto;
      grid-row: 2;
      grid-column: 2;
    }
   
    /****** Validation Icon - Valid ✅ ******/
    .spectrum-Textfield.is-valid & {
      inset-block-start: var(--mod-textfield-icon-spacing-block-valid, var(--spectrum-textfield-icon-spacing-block-valid));
      inset-block-end: var(--mod-textfield-icon-spacing-block-valid, var(--spectrum-textfield-icon-spacing-block-valid));
      inset-inline-start: var(--mod-textfield-icon-spacing-inline-start-valid, var(--spectrum-textfield-icon-spacing-inline-start-valid));
      inset-inline-end: var(--mod-textfield-icon-spacing-inline-end-valid, var(--spectrum-textfield-icon-spacing-inline-end-valid));
      color: var(--highcontrast-textfield-icon-color-valid, var(--mod-textfield-icon-color-valid, var(--spectrum-textfield-icon-color-valid)));
    }
   
    /****** Validation Icon - Invalid ⚠️ ******/
    .spectrum-Textfield.is-invalid & {
      block-size: var(--mod-textfield-icon-size-invalid, var(--spectrum-textfield-icon-size-invalid));
      inline-size: var(--mod-textfield-icon-size-invalid, var(--spectrum-textfield-icon-size-invalid));
      inset-block-start: var(--mod-textfield-icon-spacing-block-invalid, var(--spectrum-textfield-icon-spacing-block-invalid));
      inset-block-end: var(--mod-textfield-icon-spacing-block-invalid, var(--spectrum-textfield-icon-spacing-block-invalid));
      inset-inline-start: var(--mod-textfield-icon-spacing-inline-start-invalid, var(--spectrum-textfield-icon-spacing-inline-start-invalid));
      inset-inline-end: var(--mod-textfield-icon-spacing-inline-end-invalid, var(--spectrum-textfield-icon-spacing-inline-end-invalid));
      color: var(--highcontrast-textfield-icon-color-invalid, var(--mod-textfield-icon-color-invalid, var(--spectrum-textfield-icon-color-invalid)));
    }
   
    .is-disabled &,
    .is-readOnly & {
      /* Disabled validation icons are transparent */
      color: transparent;
    }
   
    .spectrum-Textfield--quiet & {
      padding-inline-end: 0;
    }
   
    .spectrum-Textfield--quiet.is-valid & {
      inset-inline-end: var(--mod-textfield-icon-spacing-inline-end-quiet-valid, var(--spectrum-textfield-icon-spacing-inline-end-quiet-valid));
    }
   
    .spectrum-Textfield--quiet.is-invalid & {
      inset-inline-end: var(--mod-textfield-icon-spacing-inline-end-quiet-invalid, var(--spectrum-textfield-icon-spacing-inline-end-quiet-invalid));
    }
   
     /* TODO - reevaluate InputGroup override after combobox is migrated - this ensures icon is not hidden under picker button */
    .spectrum-InputGroup & {
      margin-inline-end: var(--spectrum-textfield-icon-spacing-inline-end-override);
    }
  }
   
  /********* Child Component - Label *********/
  .spectrum-FieldLabel {
    .spectrum-Textfield & {
      margin-block-end: var(--mod-textfield-label-spacing-block, var(--spectrum-textfield-label-spacing-block));
      grid-row: 1;
      grid-column: 1 / span 1;
    }
   
    .spectrum-Textfield--quiet & {
      margin-block-end: var(--mod-textfield-label-spacing-block-quiet, var(--spectrum-textfield-label-spacing-block-quiet));
    }
   
    .is-disabled & {
      color: var(--spectrum-textfield-text-color-disabled);
    }
  }
   
  /********* Child Component - Help Text *********/
  .spectrum-HelpText {
    .spectrum-Textfield & {
      margin-block-start: var(--mod-textfield-helptext-spacing-block, var(--spectrum-textfield-helptext-spacing-block));
      grid-row: 3;
      grid-column: 1 / span 2;
    }
  }
   
  /********* Child Element - Character Count *********/
  .spectrum-Textfield-character-count {
    display: inline-flex;
    align-items: flex-end;
    justify-content: flex-end;
    width: auto;
    margin-block-end: var(--mod-textfield-character-count-spacing-block, var(--spectrum-textfield-character-count-spacing-block));
    margin-inline-start: var(--mod-textfield-character-count-spacing-inline, var(--spectrum-textfield-character-count-spacing-inline));
    margin-inline-end: 0;
    font-size: var(--mod-textfield-character-count-font-size, var(--spectrum-textfield-character-count-font-size));
    font-family: var(--mod-textfield-character-count-font-family, var(--spectrum-textfield-character-count-font-family));
    font-weight: var(--mod-textfield-character-count-font-weight, var(--spectrum-textfield-character-count-font-weight));
    grid-row: 1;
    grid-column: 2 / span 1;
   
    .spectrum-Textfield--quiet & {
      margin-block-end: var(--mod-textfield-character-count-spacing-block-quiet, var(--spectrum-textfield-character-count-spacing-block-quiet));
    }
  }
   
   
   
  /********* Child Element - Input *********/
  .spectrum-Textfield-input {
    box-sizing: border-box;
    inline-size: 100%;
    min-inline-size: var(--mod-textfield-min-width, var(--spectrum-textfield-min-width));
    block-size: var(--mod-textfield-height, var(--spectrum-textfield-height));
    padding-block-start: var(--mod-textfield-spacing-block-start, var(--spectrum-textfield-spacing-block-start));
    padding-block-end: var(--mod-textfield-spacing-block-end, var(--spectrum-textfield-spacing-block-end));
    padding-inline: var(--mod-textfield-spacing-inline, var(--spectrum-textfield-spacing-inline));
    /* Use padding instead of text-indent because text-indent does not left align the text in Edge browser  */
    text-indent: 0;
    vertical-align: top; /* used to align them correctly in forms. */
    outline: none;
    background-color: var(--mod-textfield-background-color, var(--spectrum-textfield-background-color));
    border: var(--mod-textfield-border-width, var(--spectrum-textfield-border-width)) solid var(--highcontrast-textfield-border-color, var(--mod-textfield-border-color, var(--spectrum-textfield-border-color)));
    border-radius: var(--mod-textfield-corner-radius, var(--spectrum-textfield-corner-radius));
    transition: border-color var(--mod-texfield-animation-duration, var(--spectrum-texfield-animation-duration)) ease-in-out;
   
    font-size: var(--mod-textfield-placeholder-font-size, var(--spectrum-textfield-placeholder-font-size));
    font-family: var(--mod-textfield-font-family, var(--spectrum-textfield-font-family));
    font-weight: var(--mod-textfield-font-weight, var(--spectrum-textfield-font-weight));
    color: var(--highcontrast-textfield-text-color-default, var(--mod-textfield-text-color-default, var(--spectrum-textfield-text-color-default)));
   
    /*** ↓ Browser Mitigations for Input ↓ ***/
    /* Remove the margin for input in Firefox and Safari. */
    margin: 0;
   
    text-overflow: ellipsis;
   
    /* Show the overflow for input in Edge. */
    overflow: visible;
   
    -webkit-appearance: none;
    /*
      Removes the native spin buttons in Firefox; -moz-appearance: none results in spinners.
      This has to come after -webkit-appearance or it gets overridden (#214)
      Details: http://stackoverflow.com/questions/23372903/hide-spinner-in-input-number-firefox-29
   
      Sets the opacity to 1 as normalize.css sets an opacity to placeholders
      Details: https://github.com/csstools/normalize.css/blob/main/normalize.css#L297
    */
    -moz-appearance: textfield;
   
    /* place in same cell: input, focus indicator, and grows sizer */
    grid-row: 2;
    grid-column: 1 / span 2;
   
    /* TODO - quiet search field left padding - reevaluate when search is migrated */
    .spectrum-Textfield--quiet .spectrum-Textfield-icon ~ & {
      padding-inline-start: calc(var(--mod--Textfield-workflow-icon-gap, var(--spectrum-Textfield-workflow-icon-gap))
                                + var(--mod-Textfield-workflow-icon-width, var(--spectrum-Textfield-workflow-icon-width)));
    }
   
    /* Remove the native clear button in IE */
    /* http://stackoverflow.com/questions/14007655/remove-ie10s-clear-field-x-button-on-certain-inputs */
    &::-ms-clear {
      inline-size: 0;
      block-size: 0;
    }
   
    /* removes the native spin buttons */
    /* http://stackoverflow.com/questions/23372903/hide-spinner-in-input-number-firefox-29 */
    &::-webkit-inner-spin-button,
    &::-webkit-outer-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }
   
    /* removes the red border that appears in Firefox */
    &:-moz-ui-invalid {
      box-shadow: none;
    }
   
    /* added to work with Edge, note, it needs double ::
     * not single : which is what autoprefixer will add
     */
    &::-ms-input-placeholder {
      opacity: 1;
    }
   
    /*** Input Placeholder Text ***/
    &::placeholder {
      opacity: 1;
      font-size: var(--mod-textfield-placeholder-font-size, var(--spectrum-textfield-placeholder-font-size));
      font-family: var(--mod-textfield-font-family, var(--spectrum-textfield-font-family));
      font-weight: var(--mod-textfield-font-weight, var(--spectrum-textfield-font-weight));
      color: var(--highcontrast-textfield-text-color-default, var(--mod-textfield-text-color-default, var(--spectrum-textfield-text-color-default)));
      transition: color var(--mod-texfield-animation-duration, var(--spectrum-texfield-animation-duration)) ease-in-out;
    }
   
    /*** Input Placeholder Text - CJK ***/
    &:lang(ja),
    &:lang(zh),
    &:lang(ko) {
      &::placeholder {
        font-style: normal;
      }
   
      &::-ms-input-placeholder {
        /* added to work with Edge, same as above */
        font-style: normal;
      }
    }
   
    /* hover */
    .spectrum-Textfield:hover &,
    &:hover {
      border-color: var(--highcontrast-textfield-border-color-hover, var(--mod-textfield-border-color-hover, var(--spectrum-textfield-border-color-hover)));
      color: var(--highcontrast-textfield-text-color-hover, var(--mod-textfield-text-color-hover, var(--spectrum-textfield-text-color-hover)));
   
      &::placeholder {
        color: var(--highcontrast-textfield-text-color-hover, var(--mod-textfield-text-color-hover, var(--spectrum-textfield-text-color-hover)));
      }
    }
   
    /* mouse focus */
    .is-focused &,
    &:focus {
      border-color: var(--highcontrast-textfield-border-color-focus, var(--mod-textfield-border-color-focus, var(--spectrum-textfield-border-color-focus)));
      color: var(--highcontrast-textfield-text-color-focus, var(--mod-textfield-text-color-focus, var(--spectrum-textfield-text-color-focus)));
   
      &::placeholder {
        color: var(--highcontrast-textfield-text-color-focus, var(--mod-textfield-text-color-focus, var(--spectrum-textfield-text-color-focus)));
      }
   
      /* focus hover */
      &:hover {
        border-color: var(--highcontrast-textfield-border-color-focus-hover, var(--mod-textfield-border-color-focus-hover, var(--spectrum-textfield-border-color-focus-hover)));
        color: var(--highcontrast-textfield-text-color-focus-hover, var(--mod-textfield-text-color-focus-hover, var(--spectrum-textfield-text-color-focus-hover)));
   
        &::placeholder {
          color: var(--highcontrast-textfield-text-color-focus-hover, var(--mod-textfield-text-color-focus-hover, var(--spectrum-textfield-text-color-focus-hover)));
        }
      }
    }
   
    /* keyboard focus */
    .is-keyboardFocused &,
    &:focus-ring,
    &:focus-visible {
      border-color: var(--highcontrast-textfield-border-color-keyboard-focus, var(--mod-textfield-border-color-keyboard-focus, var(--spectrum-textfield-border-color-keyboard-focus)));
      color: var(--highcontrast-textfield-text-color-keyboard-focus, var(--mod-textfield-text-color-focus, var(--spectrum-textfield-text-color-keyboard-focus)));
   
      &::placeholder {
        color: var(--highcontrast-textfield-text-color-keyboard-focus, var(--mod-textfield-text-color-keyboard-focus, var(--spectrum-textfield-text-color-keyboard-focus)));
      }
    }
   
    /*** Input Valid ✅ ***/
    .is-valid & {
      color: var(--highcontrast-textfield-text-color-valid, var(--mod-textfield-text-color-valid, var(--spectrum-textfield-text-color-valid)));
    }
   
    /*** Input Invalid ⚠️ ***/
    .is-invalid & {
      color: var(--highcontrast-textfield-text-color-invalid, var(--mod-textfield-text-color-invalid, var(--spectrum-textfield-text-color-invalid)));
      border-color: var(--highcontrast-textfield-border-color-invalid-default, var(--mod-textfield-border-color-invalid-default, var(--spectrum-textfield-border-color-invalid-default)));
    }
   
    /* Invalid hover */
    .is-invalid:hover &,
    .is-invalid &:hover {
      border-color: var(--highcontrast-textfield-border-color-invalid-hover, var(--mod-textfield-border-color-invalid-hover, var(--spectrum-textfield-border-color-invalid-hover)));
    }
   
    /* Invalid mouse focus */
    .is-invalid.is-focused &,
    .is-invalid:focus &,
    .is-invalid &:focus {
      border-color: var(--highcontrast-textfield-border-color-invalid-focus, var(--mod-textfield-border-color-invalid-focus, var(--spectrum-textfield-border-color-invalid-focus)));
   
      /* focus hover */
      &:hover {
        border-color: var(--highcontrast-textfield-border-color-invalid-focus-hover, var(--mod-textfield-border-color-invalid-focus-hover, var(--spectrum-textfield-border-color-invalid-focus-hover)));
      }
    }
   
    /* invalid keyboard focus */
    .is-invalid.is-keyboardFocused &,
    .is-invalid &:focus-ring,
    .is-invalid &:focus-visible {
      border-color: var(--highcontrast-textfield-border-color-invalid-keyboard-focus, var(--mod-textfield-border-color-invalid-keyboard-focus, var(--spectrum-textfield-border-color-invalid-keyboard-focus)));
    }
   
    /****** Input Disabled 🚫 ******/
    .spectrum-Textfield.is-disabled &,
    .spectrum-Textfield.is-disabled:hover &,
    &:disabled {
      background-color: var(--mod-textfield-background-color-disabled, var(--spectrum-textfield-background-color-disabled));
      border-color: transparent;
      color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-textfield-text-color-disabled)));
   
      /* For safari mobile browser */
      -webkit-text-fill-color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-textfield-text-color-disabled)));
   
      /* Disable the resize functionality when disabled */
      resize: none;
   
      /* The opacity must be set to 1 */
      opacity: 1;
   
      &::placeholder {
        color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-textfield-text-color-disabled)));
      }
    }
   
    /****** Input - Quiet 🤫 ******/
    .spectrum-Textfield--quiet & {
      border-block-start-width: 0;
      border-inline-width: 0;
      margin-block-end: var(--mod-textfield-spacing-block-quiet, var(--spectrum-textfield-spacing-block-quiet));
      padding-inline: var(--mod-textfield-spacing-inline-quiet, var(--spectrum-textfield-spacing-inline-quiet));
      background-color: transparent;
      border-radius: 0;
   
      /* Treat all quiet inputs and text areas the same */
      resize: none;
      overflow-y: hidden;
    }
   
    /****** Input - Quiet 🤫 + Disabled 🚫 ******/
    .spectrum-Textfield--quiet.is-disabled &,
    .spectrum-Textfield--quiet.is-disabled:hover &,
    &:disabled {
      background-color: transparent;
      border-color: var(--mod-textfield-border-color-disabled, var(--spectrum-textfield-border-color-disabled));
      color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-textfield-text-color-disabled)));
   
      &::placeholder {
        color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-textfield-text-color-disabled)))
      }
    }
   
    /****** Input ReadOnly ******/
    .spectrum-Textfield.is-readOnly &,
    .spectrum-Textfield.is-readOnly:hover &,
    &:read-only {
      background-color: transparent;
      border-color: transparent;
      color: var(--highcontrast-textfield-text-color-readonly, var(--mod-textfield-text-color-readonly, var(--spectrum-textfield-text-color-readonly)));
   
      &::placeholder {
        color: var(--highcontrast-textfield-text-color-readonly, var(--mod-textfield-text-color-readonly, var(--spectrum-textfield-text-color-readonly)));
        background-color: transparent;
      }
    }
  }
   
  /*** Layout Variant - Side Label ***/
  .spectrum-Textfield--sidelabel {
    grid-template-columns: auto auto auto;
    grid-template-rows: auto auto;
   
    /*** Focus Indicator ***/
    &::after {
      grid-row: 1/span 1;
      grid-column: 2/span 1;
    }
   
    .spectrum-FieldLabel {
      margin-inline-end: var(--mod-textfield-label-spacing-inline-side-label, var(--spectrum-textfield-label-spacing-inline-side-label));
      grid-row: 1/span 2;
      grid-column: 1/span 1;
    }
   
    .spectrum-Textfield-character-count {
      align-items: flex-start;
      margin-block-start: var(--mod-textfield-character-count-spacing-block-side, var(--spectrum-textfield-character-count-spacing-block-side));
      margin-inline-start: var(--mod-textfield-character-count-spacing-inline-side, var(--spectrum-textfield-character-count-spacing-inline-side));
      grid-row: 1;
      grid-column: 3/span 1;
    }
   
    .spectrum-HelpText {
      grid-row: 2;
      grid-column: 2/span 1;
    }
   
    .spectrum-Textfield-validationIcon {
      grid-row: 1/span 1;
      grid-column: 2/span 1;
    }
   
    .spectrum-Textfield-input {
      grid-row: 1/span 1;
      grid-column: 2/span 1;
    }
  }
   
  /*** Text Area ***/
  .spectrum-Textfield--multiline {
    .spectrum-Textfield-input {
      min-inline-size: var(--mod-text-area-min-inline-size, var(--spectrum-text-area-min-inline-size));
      min-block-size: var(--mod-text-area-min-block-size, var(--spectrum-text-area-min-block-size));
      resize: inherit;
    }
   
    &.spectrum-Textfield--quiet {
      .spectrum-Textfield-input {
        min-block-size: var(--mod-text-area-min-block-size-quiet, var(--spectrum-text-area-min-block-size-quiet));
        /* Treat all quiet inputs and text areas the same */
        resize: none;
        overflow-y: hidden;
      }
    }
  }