How to create a translucent text input in ReactJS ?

In this article, we are going to learn how to create a translucent text input in ReactJS.
Prerequisites:
- Knowledge of JavaScript (ES6)
- Knowledge of HTML/CSS.
- Basic knowledge of ReactJS.
React hooks used in building this application are:
JavaScript modules:
Creating React Application and Installing Modules:
Step 1: Now, you will start a new project using create-react-app so open your terminal and type:
npx create-react-app translucent-input-box
Step 2: After creating your project folder i.e. translucent-input-box , move to it using the following command.
cd translucent-input-box
Step 3: Add the npm packages you will need during the project:
npm install framer-motion styled-components
Step 5: Now open your newly created project and open the src folder and delete the following files (Optional):Â
- logo.svg
- serviceWorker.js
- setupTests.js
- index.css
- App.test.js (if any)
Create a folder named Input and create the following files:
- Component.jsx
- Component.motion.js
- Component.styles.js
Project structure: It will look like this.
Project structure
Approach:Â
- We are going to create a translucent animated text input using framer-motion and styled components.
- Wrapper, Input, Label, Underline are the styled components used to make the text input box collectively in Component.jsx file.
- In Component.jsx file, we use framer-motion with custom animation variants from the Component.motion.js file to animate the text input box.
- React useState hook is used to manage the state of value that is used as a placeholder attribute & also to set it as a label when active.
- Framer-motion useCycle hook is similar to react useState hook. It cycles through a series of visual properties used for animation. It is used to toggle between or cycle through animation variants.
Implementation:
Filename: App.js
javascript
import React, { useState } from "react"; import "./App.css";   import Input from "./Input";   const App = () => {   // The useState hook is used to manage the state of   // "value" that is used as placeholder attribute   // and also to set it as a label when clicked   const [value, setValue] = useState("");       return (     <div className="App">       <div className="container">        {/* "Input" component created using styled-components        and animated using framer-motion        */}         <Input           value={value}           onChange={(id, value) => setValue(value)}           label={"First name"}         />       </div>     </div>   ); };   export default App; |
Filename: index.js
javascript
import React from "react"; import ReactDOM from "react-dom"; Â Â import App from "./App"; Â Â const rootElement = document.getElementById("root"); ReactDOM.render( Â Â <React.StrictMode> Â Â Â Â <App /> Â Â </React.StrictMode>, Â Â rootElement ); |
Filename: App.css
css
.App { Â Â font-family: "Times New Roman", Times, serif; Â Â text-align: center; Â Â Â Â width: auto; Â Â height: 98vh; Â Â Â Â display: flex; Â Â justify-content: center; Â Â align-items: center; Â Â Â Â overflow: hidden; Â Â background: #1e9600; /* fallback for old browsers */Â Â background: -webkit-linear-gradient( Â Â Â Â to right, Â Â Â Â #ff0000, Â Â Â Â #fff200, Â Â Â Â #1e9600Â Â ); /* Chrome 10-25, Safari 5.1-6 */Â Â background: linear-gradient( Â Â Â Â to right, Â Â Â Â #ff0000, Â Â Â Â #fff200, Â Â Â Â #1e9600Â Â ); } Â Â .container { Â Â border-radius: 25px; Â Â Â Â width: 50vw; Â Â height: 20vh; Â Â Â Â display: flex; Â Â justify-content: center; Â Â align-items: center; Â Â Â Â opacity: 0.5; Â Â background-color: #f1f1f1; } Â Â Input { Â Â text-decoration: none; Â Â background-color: #f1f1f1; Â Â width: 40%; } |
Filename: Component.jsx
javascript
import React from "react"; import { Wrapper, Input, Label, Underline } from "./Component.styles"; import { motionLabel, motionUnderline } from "./Component.motion"; import { useCycle } from "framer-motion";   export default ({ label, value, onChange, id, errors }) => {   const onTapStart = (event, info) => {     focus === "inactive" && cycleFocus();     return blur === "inactive" && cycleBlur();   };   const onBlur = event => {     value === "" && cycleFocus();     cycleBlur();   };   const [focus, cycleFocus] = useCycle("inactive", "active");   const [blur, cycleBlur] = useCycle("inactive", "active");   return (    {/* Wrapper,Label,Underline - custom styled-components with           some of its attributes    */}    {/* These all collectively make the animated input box which    then given transluscent background using CSS    */}     <Wrapper>       <Input         onTap={onTapStart}         placeholder={label}         onBlur={e => onBlur(id)}         onChange={e => onChange(id, e.target.value)}         type={"text"}         required         value={value}       />       <Label {...motionLabel(focus)}>{label}</Label>       <Underline {...motionUnderline(blur)} />     </Wrapper>   ); |
Filename: Component.motion.js
javascript
const variantsWrapper = {   initial: {},   in: {},   out: {},   hover: {},   tap: {} };   const variantsLabel = {   active: {     x: -15,     y: -20,     scale: 0.7   },   inactive: { x: 0, y: 0, scale: 1 } }; const variantsUnderline = {   active: {     width: "100%",     transition: {       ease: "easeIn",       duration: 0.2     }   },   inactive: {     width: "0",     transition: {       ease: "easeIn",       duration: 0.1     }   } };   export const motionLabel = state => {   return {     animate: state,     variants: variantsLabel   }; };   export const motionUnderline = state => {   return {     animate: state,     variants: variantsUnderline   }; };   export const animationWrapper = {   initial: "initial",   animate: "in",   exit: "out",   whileHover: "hover",   whileTap: "tap",   variants: variantsWrapper }; |
Filename: Component.styles.js
javascript
import styled from "styled-components"; import { motion } from "framer-motion";   // Below are the styled-components used to // make the animated text input box   export const Wrapper = styled(motion.div)`   position: relative;   width: 80%;   padding: 18px;   padding-bottom: 30px;   border-bottom: 1px solid #2f528f; `;   export const Label = styled(motion.span)`   align-self: center;   position: absolute;   left: 0;   top: 50%;   grid-area: input;   font-family: Montserrat;   font-size: 18px;   line-height: 18px;   text-align: left;   pointer-events: none;   font-weight: normal;   /* background: green; */`;   export const Input = styled(motion.input)`   height: 18px;   font-size: 18px;   -webkit-appearance: none;   background: transparent !important;   position: absolute;   left: 0;   top: 50%;   padding: 0;   padding-bottom: 5px;   margin: 0;   color: black;   border: none;   box-shadow: none !important;   font-weight: normal;   &:focus {     outline: none;   }   &::placeholder {     color: #f1f1f1;   } `;   export const Underline = styled(motion.div)`   position: absolute;   background-color: #2f528f;   bottom: 0;   left: 0;   width: 100%;   height: 3px; `; |
Step to Run Application: Run the application using the following command from the root directory of the project :
npm start
Output: Now open your browser and go to http://localhost:3000/, you will see the following output:



