Search code examples
cssreactjsstyled-components

Why isn't CSS :focus pseudoselector working as expected in Chrome?


I have a simple form. When the user focuses on an input, the label should move up. It works fine in Firefox (as can be seen in video), but not in Chrome. In chrome, the text is stuck in the end position. When I change text color in the :focus + span code block, it applies automatically, which tells me that the elements are constantly focused.

import React from 'react'
import styled from 'styled-components'
import { useState, useEffect } from 'react';

function PersonalInfo() {
const [firstAndLastName, setfirstAndLastName] = useState(JSON.parse(sessionStorage.getItem('FirstAndLastName' ?? '')));
const [email, setEmail] = useState(JSON.parse(sessionStorage.getItem('email' ?? '')));
const [companyName, setCompanyName] = useState(JSON.parse(sessionStorage.getItem('companyName' ?? '')));
const [companyIndustry, setCompanyIndustry] = useState(JSON.parse(sessionStorage.getItem('companyIndustry' ?? '')));

const handleNameChange = (e) => {
  // console.log(firstAndLastName)
  sessionStorage.setItem('FirstAndLastName', JSON.stringify(e.target.value));
  setfirstAndLastName(e.target.value)
}

const handleEmailChange = (e) => {
  // console.log(email)
  sessionStorage.setItem('email', JSON.stringify(e.target.value));
  setEmail(e.target.value)
}

const handleCompanyNameChange = (e) => {
  // console.log(companyName)
  sessionStorage.setItem('companyName', JSON.stringify(e.target.value));
  setCompanyName(e.target.value)
}

const handleCompanyIndustryChange = (e) => {
  // console.log(companyIndustry)
  sessionStorage.setItem('companyIndustry', JSON.stringify(e.target.value));
  setCompanyIndustry(e.target.value)
}


  return (
    <PersonalInfoContainer>
      <InputContainer>
        <Input 
        name="user_name" 
        type='text' 
        value={firstAndLastName} 
        onChange={handleNameChange} 
        placeholder=''/>
        <Label>First and Last Name</Label>
      </InputContainer>
      <InputContainer>
        <Input  
        name='user_email' 
        type='email' 
        value={email} 
        onChange={handleEmailChange} 
        placeholder=''/>
        <Label>Email</Label>
      </InputContainer>
      <InputContainer>
        <Input 
        name='user_companyName' 
        type='text' 
        value={companyName} 
        onChange={handleCompanyNameChange} 
        placeholder=''/>
        <Label>Company Name</Label>
      </InputContainer>
      <InputContainer>
        <Input 
        name='user_companyIndustry' 
        type='text' 
        value={companyIndustry} 
        onChange={handleCompanyIndustryChange} 
        placeholder=''/>
        <Label>Company Industry</Label>
      </InputContainer>
    </PersonalInfoContainer>
  )
}

const PersonalInfoContainer = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 30vh;
  margin-bottom: 3rem;
`;

const InputContainer = styled.div`
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Label = styled.span`
  position: absolute;
  left: 0;
  padding-left: .2rem;
  font-size: 1rem;
  color: #e6e5e5;
  pointer-events: none;
  transition: 0.6s;
`;

const Input = styled.input`
  width: 100%;
  padding: .6rem 1.2rem;
  border: none;
  font-size: .9rem;
  font-size: 1rem;
  outline-color: transparent;
  background-color: transparent;
  border-bottom: 2px solid #e6e5e5;
  color: white;

  &:focus {
    border-bottom: 2px solid #fff;
  }

  &:not(:placeholder-shown) + span,
  &:focus + span {
    color: white;
    transform: translateX(10px);
    transform: translateY(-25px);
    font-size: 0.75rem;
   } 
`;

export default PersonalInfo

Sandbox: https://codesandbox.io/s/personal-info-form-component-h9652x


Solution

  • The standard at 13.1.3. The Placeholder-shown Pseudo-class: :placeholder-shown says:

    Input elements can sometimes show placeholder text as a hint to the user on what to type in. See, for example, the placeholder attribute in [HTML5]. The :placeholder-shown pseudo-class matches an input element that is showing such placeholder text, whether that text is given by an attribute or a real element, or is otherwise implied by the UA.

    In your case, however, you have placeholder='' as a placeholder which displays nothing. Firefox and Chrome right now don't agree on if "displaying" an empty placeholder counts as displaying. I believe that Chrome is right in that case and not Firefox.

    A solution to your problem is to set placeholder to an actual value (which you should do anyways) and make the placeholder text transparent.

    input::placeholder {
       color: transparent;
    }