React styled component animation not working - css

I am trying to create an animation for form textfield and label.
I want to be able to change the position of LabelText to top of the TextBox component.
Please let me know what I am missing on, My entered text and label are overlapping i.e. label is not animated.
Request help!
Styled components:
export const TextBox = styled.input`
display: flex;
width: 100%;
height: 2em;
border-radius: 5px;
border: none;
background: ${styles.backgroundGradient};
`;
export const LabelText = styled.label`
position: absolute;
top: 0;
left: 0;
font-size: 18px;
line-height: 16px;
pointer-events: none;
transition: 0.5s;
color: ${styles.formContentColor};
${TextBox}:focus ~ &,
${TextBox}:not([value=""]) ~ & {
top: -1.5em;
left: 0;
color: ${styles.formContentColor};
font-size: 20px;
}
`;
export const InputWrapper = styled.div`
position: relative;
width: 60%;
`;
Order of placement in components
<InputWrapper>
<LabelText>Product Name</LabelText>
<TextBox type="text" />
</InputWrapper>

I read through comment by #mosh feu and other answers on stackoverflow.
Detect if an input has text in it using CSS -- on a page I am visiting and do not control?
There are couple of approaches that can serve the purpose i.e. to check whether input field is empty or not drafting them below for future refrrence.
input:not(:placeholder-shown):
input:not([value=""]):
In my case input is value of TextBox.
export const LabelText = styled.label`
position: absolute;
top: 1.5em;
left: 0;
font-size: 18px;
line-height: 16px;
pointer-events: none;
transition: 0.6s;
color: ${styles.formContentColor};
${TextBox}:focus ~ &,
${TextBox}:not(:placeholder-shown) ~ & {
top: 0;
left: 0;
color: ${styles.formContentColor};
font-size: 16px;
}
`;

Related

Is there a way to change the background color of a parent element when a radio button is clicked without jQuery?

The code structure looks somewhat like this
function RenderOptions() {
return allOptions.map((val) => {
return (
<>
<label htmlFor={val}>
<input
type="radio"
name="options"
id={val}
value={val}
className="check-btn"
/>{" "}
<span className="text-inner">{val}</span>
</label>{" "}
</>
);
});
}
Didn't put a div since I didn't want to spend some time finding how to align the buttons in rows.
CSS
.check-btn {
opacity: 0;
position: relative;
top: 2px;
}
label {
border-radius: 10px;
font-family: Inter;
font-style: normal;
font-weight: 600;
font-size: 12px;
line-height: 12px;
text-align: center;
width: 100%;
transition: 0.3s ease;
background: #f5f7fb;
border: 0.794239px solid #4d5b9e;
box-sizing: border-box;
border-radius: 7.94239px;
padding-top: 5px;
padding-bottom: 5px;
padding: 5px 10px 5px 10px;
}
label:hover {
background-color: #d6dbf5;
cursor: pointer;
}
.text-inner {
position: relative;
right: 10px;
}
I'm trying to change the background color of the parent label when the radio button is checked. Can do it the CSS way or the React way provided only 1 button from each sets color changes.
and if another option is clicked ->
TL;DR. See the CodePen sample I prepared for you here, and the snippet below.
In this example, I simply used the useState hook to keep track of the current radio selection, and applied its value as data attribute to label tag. Then you can use CSS to style it as needed.
const App = () => {
const [chosenOne, setChosenOne] = React.useState();
const list = ["Alec Baldwin", "Bruce Willis", "Dwayne Johnson", "Jamie Fox"];
return (
<div>
{list.map((person, i) => (
<label key={i} htmlFor={person} data-chosen={chosenOne === person}>
<input type="radio" name="options" id={person} value={person} className="check-btn" onChange={(e) => setChosenOne(e.target.value)}/>
<span className="text-inner">{person}</span>
</label>
))}
</div>
)
}
.check-btn {
opacity: 0;
position: relative;
top: 2px;
}
label {
border-radius: 10px;
font-family: Inter;
font-style: normal;
font-weight: 600;
font-size: 12px;
line-height: 12px;
text-align: center;
width: 100%;
transition: 0.3s ease;
background: #f5f7fb;
border: 0.794239px solid #4d5b9e;
box-sizing: border-box;
border-radius: 7.94239px;
padding-top: 5px;
padding-bottom: 5px;
padding: 5px 10px 5px 10px;
}
label:hover, label[data-chosen="true"] {
background-color: #d6dbf5;
cursor: pointer;
}
.text-inner {
position: relative;
right: 10px;
}
label + label {
margin-left: .5rem;
}
You could do that with CSS or the style prop in React.
I'm assuming your storing the state of the radio buttons somewhere?
When you map through the array, you can check if the current radio button's value is equal to the value of the current state. If they are the same, you can add the class or style to style the label.

:Active works in styled components but :checked doesn't

I am attempting to transition from css to styled components. I am creating a toggle switch component. The animation on the :active class works when the switch is checked but, when the checkbox is checked the switch does not move to the left like it would with just normal css.
import React from 'react';
import styled from 'styled-components'
const Button = styled.span`
content: '';
position: absolute;
top: 3.7px;
left: 5px;
width: 42px;
height: 42px;
border-radius: 45px;
transition: 0.2s;
background: #fff;
box-shadow: 0 0 2px 0 rgba(10, 10, 10, 0.29);
`;
const Label = styled.label`
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
width: 100px;
height: 50px;
background: dodgerblue;
border-radius: 100px;
position: relative;
transition: background-color 0.2s;
&:active ${Button} {
width: 50px;
}
`;
const Input = styled.input`
height: 0;
width: 0;
visibility: hidden;
&:checked ${Button} {
left: calc(100% - 5px);
transform: translateX(-100%);
}
`;
const Switch = ({ isOn, handleToggle, onColor }) => {
return (
<>
<Input
checked={isOn}
onChange={handleToggle}
className='react-switch-checkbox'
id={`react-switch-new`}
type='checkbox'
/>
<Label
style={{ background: isOn && onColor }}
className='react-switch-label'
htmlFor={`react-switch-new`}>
<Button className={`react-switch-button`} />
</Label>
</>
);
};
export default Switch;
Your problem is not related to styled components. The rule &:checked ${Button} { assumes the Button is a child of Input, but it's actually a child of Input's sibling Label.
Update the styled component rule to:
&:checked + ${Label} ${Button} {
left: calc(100% - 5px);
transform: translateX(-100%);
}
Sandbox

Is there a way to modify '&:before/:after' to give a dynamic property?

A styled-component that has &:before attribute that I want to give access to a dynamic color property. But I'm lost to how to apply that.
I've Tried passing the props to <Hover /> and it works. But the Triangle in &:before cannot access that.
const Hover = styled.div`
padding:7px;
margin: -102px auto;
border-style: solid;
border-radius: 15px;
border-width: 3px;
text-align: left;
font-weight: 400;
font-size: 19px;
color: #000000;
font-family: sans-serif;
position: absolute;
left:-15px;
z-index:10;
&:before {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid ;
border-right: 10px solid transparent;
border-top: 10px solid ;
border-bottom: 10px solid transparent;
left: 19px;
bottom: -19px;
z-index:10;
}
`;
As a single styled-component the following class is:
class MarkerHover extends Component {
render() {
const {color, children}= this.props
return (
<Hover style={{backgroundColor: color }}>
{...children}
</Hover>
);
}
}
export default MarkerHover;
I expect to have a whole colored Window after successfully passing the color props to the &:before division.
As the documentation of Styled Components states (see https://www.styled-components.com/docs/basics#passed-props) you can read passed props:
const Hover = styled.div`
color: ${props => props.color};
`;
when you pass them like this:
<Hover color="#f00" />
You can use that same prop in your pseudo-element as well:
const Hover = styled.div`
color: ${props => props.color};
&::before {
background: ${props => props.color};
}
`;
So don't use the style attribute on your styled component, but pass regular props.
If you want to apply a CSS rule only after a certain condition, you can do that like this:
const Hover = styled.div`
color: #ccc;
&::before {
content: "";
padding: 16px;
${props => props.withBg ? `background-color: ${props.withBg}` : ''}
}
`;
With background:
<Hover withBg="#f00" />
Without background:
<Hover />

Button positioning different on iOS then Windows and Android

I have a span what has 2 elements, input and svg.
I want the svg to be centered vertically in the input field.
I have 3 devices where I'm testing the design of my PWA.
Windows 10 - Google Chrome
Android 6.0 - Google Chrome
iOS 12.+ - Safari
On both Windows and Android it's centered vertically, only not on the iOS device.
Does anyone have an idea what this would fix?
React Component:
<StyledInputSpan>
<StyledInput />
<StyledClearButton />
</StyledInputSpan>
Styled Component:
export const StyledInput = styled.input`
//Reset box-shadow
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
padding: 0.75em 2em 0.75em 0.75em; //Extra padding on the right for the clear button.
font-size: 1em;
//Hide the standard clear button.
&[type=search]::-webkit-search-cancel-button {
display: none;
}
`;
export const StyledClearButton = styled.button`
position: absolute;
top: calc(2.8em - env(safe-area-inset-top)); //env() is for the nodge on iOS.
right: 0;
`;
const StyledInputSpan = styled.span`
display: flex;
align-items: center;
`;
Find out that using env(safe-area-inset-top) is not what I was looking for.
env(safe-area-inset-top) works only for the top of your app on iOS.
When you use env(safe-area-inset-top) it push down your app with the height of the nodge.
I changed my css/styled component to:
export const StyledInput = styled.input`
//Reset box-shadow
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
position: relative;
display: block;
padding: 0.75em 2em 0.75em 0.75em; //Extra padding on the right for the clear button.
font-size: 1em;
//Hide the standard clear button.
&[type=search]::-webkit-search-cancel-button {
display: none;
}
`;
export const StyledClearButton = styled.button`
position: absolute;
top: 27.5%;
transform: translate(0, -50%);
right: 0;
`;
const StyledInputSpan = styled.span`
position: relative;
display: flex;
align-items: center;
`;

Expanding Search Bar on External Button Click

I want to have a search input expand & transition on the click of an external button(icon) instead of just appearing/disappearing on click. How would one go about doing this. Either with pure CSS or in an Angular 7 animation way. I'm learning Angular for the first time.
Thanks
I want it to do something just like the search bar on this site.
https://theother98.com/
What I Have Thus Far w/ Angular 7
NAV.COMPONENT.HTML // in order to toggle hidden or shown searchbar
<div href="#" (click)="onToggleSearch()" class="search-icon"><i class="fa fa-search"></i></div>
<input type="text" [ngClass]="toggleSearch ? 'show' : 'hide'" name="search" placeholder="What are you looking for?">
NAV.COMPONENT.TS // some JS that allows the toggle method to work
export class NavComponent implements OnInit {
toggleSearch: boolean = false;
constructor() { }
ngOnInit() {
}
onToggleSearch() {
this.toggleSearch = !this.toggleSearch;
}
NAV.COMPONENT.SCSS // basic scss of my searchbar
input {
flex: 1;
z-index: 999;
font-size: 14px;
width: 180px;
border: none;
outline: none;
padding: 8px;
margin-right: 10px;
transition: all 0.15s ease-in-out;
}
I figured it out for anyone who had similar dilemma. What I did was this.
.show {
display: block;
max-width: 200px;
transform: scale(1);
}
.hide {
display: none;
max-width: 0px;
transform: scale(0);
}
input {
flex: 1;
z-index: 999;
font-size: 14px;
width: 180px;
border: none;
outline: none;
padding: 10px 8px;
margin-right: 10px;
display: block;
transition: all 0.3s ease-in-out;
}
When defining the CSS without transform:scale() the input will not be completely hidden when .hide is added to the element. Also, when you add a max height & max width and then click the button to display the searchbar... The input will not transition fluidly, instead it expands to the max height and THEN to the max width, in a very inelegant way. Finally, adding display:block to the input element is essential.
Thanks for the help everyone!
You are adding the classes hide and show. Therefore, having a max-height defined in those classes and a display of block on the item that will be "moving" should allow your transition to work. For example:
.hide {
max-height: 0;
}
.show {
max-height: 1000px;
}
input {
flex: 1;
z-index: 999;
font-size: 14px;
width: 180px;
border: none;
outline: none;
padding: 8px;
margin-right: 10px;
transition: all 0.15s ease-in-out;
display: block;
}

Resources