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:



