I'm trying to create a password validator with certain regex condition in material UI that changes from bullet point to checkbox when conditions are met.
So far I've tried using the npm library: NiceInputPassword however this doesn't let me change the state as easily so I'm going back to my regular Material UI. I've read documentation on lists in material UI but I couldn't find anything that allows me to change bullet points to checkboxes as shown in the image.
CodePudding user response:
There are a few bits to this to achieve your outcome using the libraries and components, so I'll try to explain as best I can.
React-Nice-Input-Password accepts a prop to provide a custom class name for each of the states and specifically for success you can use <NiceInputPassword successClassName="custom-success"
. With that added you are now able to style the bullet points and by using the same CSS selectors with your own custom-success
name you can set the final style, .input-password__description li.custom-success:before
. Note you may be able to provide a less specific selector but I didn't investigate this.
Now for the styles comes the interesting part. Set background-color: transparent
so you don't see the current style applied, then add a background image with a
Supporting links:
- how to change svg fill color when used as base-64 background image data?
- How can I use a Material Design Icon as a CSS background-image value?
CodePudding user response:
I think you can meet all your requirements using @mui/material and @mui/icons-material libraries like this:
import { TextField } from "@mui/material";
import { useEffect, useState } from "react";
import "./styles.css";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import CircleIcon from "@mui/icons-material/Circle";
function checkUppercase(str) {
for (let i = 0; i < str.length; i ) {
if (
str.charAt(i) === str.charAt(i).toUpperCase() &&
str.charAt(i).match(/[a-z]/i)
) {
return true;
}
}
return false;
}
const SPECIAL_CHARS = "!@#$%^&*()";
function checkSpecialChars(str) {
const alreadyFoundChars = [];
for (let i = 0; i < str.length; i ) {
const currentChar = str[i];
if (!alreadyFoundChars.includes(currentChar)) {
if (SPECIAL_CHARS.includes(currentChar)) {
alreadyFoundChars.push(currentChar);
}
}
}
return alreadyFoundChars.length >= 3;
}
const getIcon = (isChecked) => {
const smallDotIcon = <CircleIcon sx={{ fontSize: "0.4rem" }} />;
const checkCircleIcon = <CheckCircleIcon sx={{ fontSize: "0.8rem" }} />;
const iconToBeRendered = isChecked ? checkCircleIcon : smallDotIcon;
return (
<div
style={{
height: "20px",
width: "15px",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
{iconToBeRendered}
</div>
);
};
const prepareHelperText = (value) => {
const firstIcon = getIcon(value.length >= 8);
const secondIcon = getIcon(checkUppercase(value));
const thirdIcon = getIcon(checkSpecialChars(value));
return (
<div>
<div style={{ display: "flex" }}>
{firstIcon}
Must contain at least 8 characters
</div>
<div style={{ display: "flex" }}>
{secondIcon} Must contain at least 1 uppercase letter
</div>
<div style={{ display: "flex" }}>
{thirdIcon} Must contain 3 of the 4 types of characters !@#$%^&*()
</div>
</div>
);
};
export default function App() {
const [value, setValue] = useState("");
const [helperText, setHelperText] = useState("");
useEffect(() => {
setHelperText(prepareHelperText(value));
}, [value]);
return (
<div className="App">
<TextField
type="password"
label="Password"
value={value}
onChange={(e) => setValue(e.target.value)}
helperText={helperText}
sx={{
"& .Mui-focused": {
color: "purple"
},
"& label.Mui-focused": {
color: "purple !important"
},
"& .MuiOutlinedInput-root": {
"&.Mui-focused fieldset": {
borderColor: "purple"
}
}
}}
/>
</div>
);
}
You can take a look at this sandbox for a live working example of this solution.