CSS selector when placeholder shown in grid element

Viewed 26

In a (React/TS) form i need to move the label for the inputfield when;

  • The input has the focus
  • When the placeholder is not shown

This works fine for the first objective (with .grid__item--fixedrowcolone), but i am unable to to realise this for the second. The input and the label are grid elements so i can place the input and label on top and vertically center both.

What i unsuccessfully tried is (multiple variants) of the snippet below.

.grid__item--fixedrowcolone {
  &:not(~ .form__inputfield:placeholder-shown) {
    color: green;
  }
}

react form

 <div className={styles.form__inputwrapper} data-testid='form-input'>
      <div className={styles.form__inputsymbol} data-testid='form-input-icon'>
        <img src={lockSvg} alt='lock' width='24' height='24' />
      </div>
      <div className={styles.grid__container} data-testid='form-input-field'>
        <div className={styles['grid__item--fixedrowcolone']}>
          <input
            className={styles.form__inputfield}
            type='text'
            pattern='^.*{8,}'
            id='pwd1'
            name='pwd1'
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
            placeholder=' '
            required
            data-testid='forminput-input'
          />
        </div>

        <div className={styles['grid__item--fixedrowcoltwo']}>
          <label
            className={styles.form__inputlabel}
            htmlFor='pwd1'
            data-testid='forminput-inputlabel'
          >
            wachtwoord
            <span className={styles.form__inputlabelvalmsg}>
              +312234
            </span>
          </label>
        </div>
      </div>
    </div>

css module.scss

.grid {
  &__container {
    display: grid;
    justify-items: stretch;
  }

  &__item {
    &--fixedrowcolone, &--fixedrowcoltwo {
      display: flex;
      grid-column: 1;
      grid-row: 1;
    }
  }
}

.form {

  &__inputwrapper {
    display: flex;
    margin-bottom: 10px;
    position: relative;
    background: var(--theme_form_field_bg_color);
    border-radius: 4px;
  }

  &__inputsymbol {
    display: flex;
    align-self: center;
    //align-items: center;
    padding-left: 10px;
    pointer-events: none;
    color: var(--theme_fg_color);
    font-size: 1.5em;
    transition: all 0.4s;
    filter: var(--theme_fg_color_filter)
  }

  &__inputfield {
    align-self: center;
    //line-height: 1.2;
    font-size: 1.5em;
    height: 50px;
    color: var(--theme_fg_color);
    background: none;
    outline: none;
    border: none;
    max-width: 280px;
    min-width: 250px;
    overflow: visible;
    touch-action: manipulation;
  }

  &__inputlabel {
    align-self: center;
    //line-height: 1.2;
    font-size: 1.5em;
    transition: .3s all ease;
  }

  &__inputlabelvalmsg {
    display: none;
  }

}

.grid__item--fixedrowcolone {
  &:focus-within ~ .grid__item--fixedrowcoltwo {
    top: 5px;
    font-size: .5em;
    align-self: start;
  }
}
1 Answers

Unfortunately it is yet not possible to select elements based on presence of child elements or child element pseudo selectors. So therefore i reverted back to absolute positioning to overlay two elements.

react form

    <div className={styles.form__inputwrapper} data-testid='form-input'>
      <div className={styles.form__inputsymbol} data-testid='form-input-icon'>
        <img src={lockSvg} alt='lock' width='24' height='24' />
      </div>
      <div
        className={styles.form__inputfieldwrapper}
        data-testid='form-input-field'
      >
        <input
          className={styles.form__inputfield}
          type='text'
          pattern='^.*{8,}'
          id='pwd1'
          name='pwd1'
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          placeholder=' '
          required
          data-testid='forminput-input'
        />
        <label
          className={styles.form__inputlabel}
          htmlFor='pwd1'
          data-testid='forminput-inputlabel'
        >
          wachtwoord
          <span className={styles.form__inputlabelvalmsg}>
            +31652693 of 0652786518
          </span>
        </label>
      </div>
    </div>

css module.scss

@mixin inputlabel-defaults() {
  font-size: 1.5em;
  align-self: center;
}

.form {

  &__inputwrapper {
    display: flex;
    margin-bottom: 10px;
    position: relative;
    background: var(--theme_form_field_bg_color);
    border-radius: 4px;
  }

  &__inputfieldwrapper {
    display: flex;
  }

  &__inputsymbol {
    display: flex;
    align-self: center;
    //align-items: center;
    padding-left: 10px;
    pointer-events: none;
    color: var(--theme_fg_color);
    font-size: 1.5em;
    transition: all 0.4s;
    filter: var(--theme_fg_color_filter)
  }

  &__inputlabel {
    position: absolute;
    transition: .3s all ease;
    @include inputlabel-defaults();
  }

  &__inputlabelvalmsg {
    display: none;
  }

  &__inputfield {
    align-self: center;
    //line-height: 1.2;
    font-size: 1.5em;
    height: 50px;
    color: var(--theme_fg_color);
    background: none;
    outline: none;
    border: none;
    max-width: 280px;
    min-width: 250px;
    overflow: visible;
    touch-action: manipulation;

    &:focus-within ~ .form__inputlabel {
      top: 5px;
      font-size: .5em;
      align-self: start;
    }

    &:not(:placeholder-shown) ~ .form__inputlabel {
      color: red;
      top: 5px;
      font-size: .5em;
      align-self: start;
    }

    &:placeholder-shown ~ .form__inputlabel {
      top: unset;
      @include inputlabel-defaults();
    }

  }

}

Related