Skip to content

Instantly share code, notes, and snippets.

@aibolik
Created October 8, 2022 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aibolik/5606dec29e1c3334fbd32c8d16ad561d to your computer and use it in GitHub Desktop.
Save aibolik/5606dec29e1c3334fbd32c8d16ad561d to your computer and use it in GitHub Desktop.
Catchy form implementation from this tweet: https://twitter.com/fracasosEnUX/status/1578437617452224513
import { useRef, useState } from "react";
import styled, { createGlobalStyle } from "styled-components";
const GlobalStyles = createGlobalStyle`
body {
color: #494E5C;
}
`;
const Wrapper = styled.div`
font-size: 16px;
background: hsl(212, 35%, 9.2%);
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
`;
const FormWrapper = styled.div`
max-width: 350px;
width: 100%;
margin: auto;
`;
const InputsWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 12px;
`;
const Input = styled.input`
border: 1px solid var(--blue6);
border-radius: 4px;
padding: 16px 12px;
:focus {
outline-color: var(--blue7);
}
`;
const Button = styled.button`
border: none;
border-radius: 4px;
padding: 16px 12px;
margin-top: 12px;
cursor: pointer;
transition: background 0.3s, transform 0.3s;
${(props: { valid: boolean }) =>
props.valid
? `
background: var(--grass3);
color: var(--grass12);
`
: `
background: var(--blue3);
color: var(--blue12);
`}
`;
function isValidData(username: string, password: string) {
if (!username.length || !password?.length) {
return false;
}
if (username.length < 4 || password.length < 6) {
return false;
}
if (
password.toLowerCase() === password ||
password.toUpperCase() === password
) {
return false;
}
return true;
}
export default function CatchForm() {
const formRef = useRef<HTMLFormElement>(null);
const btnRef = useRef<HTMLButtonElement>(null);
const [isValid, setIsValid] = useState<boolean>(false);
const [transform, setTransform] = useState("0");
const onChange = () => {
const form = formRef.current;
if (!form) {
return;
}
// @ts-ignore
const username = form["username"].value;
// @ts-ignore
const password = form["password"].value;
setIsValid(isValidData(username, password));
};
const onMouseOver = () => {
if (isValid) {
return;
}
if (transform === '0') {
setTransform('200px');
} else {
setTransform('0');
}
};
const onSubmit: React.FormEventHandler = (e) => {
e.preventDefault();
}
return (
<>
<GlobalStyles />
<Wrapper>
<FormWrapper>
<form onChange={onChange} ref={formRef} onSubmit={onSubmit}>
<InputsWrapper>
<Input name="username" placeholder="username" type="text" />
<Input name="password" placeholder="password" type="password" />
</InputsWrapper>
<Button
ref={btnRef}
type="submit"
valid={isValid}
onMouseOver={onMouseOver}
style={{ transform: `translateX(${transform})` }}
>
Submit
</Button>
</form>
</FormWrapper>
</Wrapper>
</>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment