Search code examples
reactjstailwind-css

How to keep the floating label up when input is not empty


So to sum up everything: I am using NextJs, React and Tailwind. I created a floating label code for which I took from https://flowbite.com/docs/forms/floating-label/. In the flowbite example the label is kept on top when the input is not empty, I am trying to achieve the same result with pure tailwind.I assume there are some behind the scenes classes that set the styles for this floating label that actually keep it on top in the flowbite example, but the inline-styles there don't do the trick. I have seen examples of how to solve it with JQuery, but it is irrelevant in my case.

'use client'
import { ChangeEvent } from "react"


type InputFieldProps = {
name: string, 
onChange: (e: ChangeEvent<HTMLInputElement>) => void,
id: string,
type: string,
htmlFor: string,
value: string,
}


const InputField: React.FC<InputFieldProps> = ({ name, id, type, htmlFor, value, onChange }) => {


    return (
      <div className="relative">

        <input
          type={type}
          id={id}
          value={value}
          onChange={onChange}
          className={`font-roboto tracking-body-large w-[360px] h-[40px] px-2 text-base text-gray-900 bg-transparent rounded-[4px] border-[1px] border-[#CAC4D0] focus:outline-none focus:border-[#6750A4] peer`}
          required
        />
        <label
          htmlFor={htmlFor}
          className={`absolute text-base text-[#49454F] peer-focus:text-[#6750A4] duration-300 transform scale-75 top-2 z-10 origin-[0] bg-white px-2 peer-focus:px-2 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-[-0.25rem] peer-focus:scale-50 peer-focus:-translate-y-2 start-1 hover:cursor-text ${value ? '' : '' }`}
        >
          {name}
        </label>
      </div>
    );
  };
  
  export default InputField;

Solution

  • Have the peer-placeholder-shown: and peer-focus: classes only applied when the value is empty. When value is not empty, have the peer-focus: classes applied but without the peer-focus: variant attached:

    const InputField = ({ name, id, type, htmlFor, value, onChange }) => {
      return (
        <div className="relative">
          <input
            type={type}
            id={id}
            value={value}
            onChange={onChange}
            className={`font-roboto tracking-body-large w-[360px] h-[40px] px-2 text-base text-gray-900 bg-transparent rounded-[4px] border-[1px] border-[#CAC4D0] focus:outline-none focus:border-[#6750A4] peer`}
            required
          />
          <label
            htmlFor={htmlFor}
            className={`absolute text-base text-[#49454F] peer-focus:text-[#6750A4] duration-300 top-2 z-10 origin-[0] bg-white px-2 start-1 hover:cursor-text ${
              value ? "top-[-0.25rem] scale-50 -translate-y-2" : "scale-75 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-[-0.25rem] peer-focus:scale-50 peer-focus:-translate-y-2"
            }`}
          >
            {name}
          </label>
        </div>
      );
    };
    
    function App() {
      const [value, setValue] = React.useState('');
      return <InputField
        name="foo"
        id="foo"
        type="text"
        htmlFor="foo"
        value={value}
        onChange={({ target }) => setValue(target.value)}
      />
    }
    
    ReactDOM.createRoot(document.getElementById("app")).render(<App />);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js" integrity="sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js" integrity="sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.tailwindcss.com/3.3.5"></script>
    
    <div id="app"></div>