custom label on select as floating - javascript

I am trying to create a floating label select component, So the select box will have a label on click of that it will show a dropdown options. Like this With an icon and override the native browser options.
I was able to achieve using input field, but i am not able to understand how to create such a like component.
Dropdown.js
import React from "react";
import {
DropdownWrapper,
StyledSelect,
StyledOption,
StyledLabel
} from "./style";
export function Dropdown(props) {
return (
<DropdownWrapper onChange={props.onChange}>
<StyledLabel htmlFor={props.id}>{props.formLabel}</StyledLabel>
<StyledSelect id={props.id} name={props.id}>
{props.children}
</StyledSelect>
</DropdownWrapper>
);
}
export function Option(props) {
return <StyledOption selected={props.selected}>{props.value}</StyledOption>;
}
Style.js
import styled from "#emotion/styled";
export const DropdownWrapper = styled.div`
display: flex;
flex-flow: column;
justify-content: flex-start;
`;
export const StyledSelect = styled.select`
height: 100%;
padding: 0.5rem 0;
margin-bottom: 1rem;
border: none;
border-bottom: 1px solid black;
outline: none;
-webkit-appearance: none;
-moz-appearance: none;
text-indent: 1px;
text-overflow: "";
`;
export const StyledOption = styled.option`
color: ${(props) => (props.selected ? "lightgrey" : "black")};
`;
export const StyledLabel = styled.label`
margin-bottom: 1rem;
`;
Any help appreciated, here is what i have tried so far. link

Related

React js app sidebar selected item not highlighted

I created this react app with a side bar, and it looks pretty good, but one thing I can't figure out is how to mark the item (page link) that was clicked.
Here is the code, I added activeClassName="selected" to the SidebarLink const, and added it to the styled-component, but it's not working.
import React, { useState } from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";
const SidebarLink = styled(Link)`
/*border: 3px solid green;*/
display: flex;
color: #e1e9fc;
justify-content: space-between;
align-items: center;
padding: 20px;
list-style: none;
height: 60px;
text-decoration: none;
font-size: 18px;
&:hover {
background: #252831;
border-left: 4px solid #ffbc2e;
cursor: pointer;
}
.selected {
color: red;
}
`;
const SidebarLabel = styled.span`
margin-left: 16px;
`;
/* Used for Training dropdown */
const DropdownLink = styled(Link)`
/*border: 3px solid red;*/
background: #252831;
height: 60px;
padding-left: 3rem;
display: flex;
align-items: center;
text-decoration: none;
color: #f5f5f5;
font-size: 16px;
font-weight: bold;
&:hover {
background: #48526F;
border-left: 4px solid #ffbc2e;
cursor: pointer;
}
`;
const SubMenu = ({ item }) => {
const [subnav, setSubnav] = useState(false);
const showSubnav = () => setSubnav(!subnav);
return (
<>
<SidebarLink to={item.path} onClick={item.subNav && showSubnav} activeClassName="selected" exact>
<div className="sidebarTextContainer">
<div className="sidebarIcon">{item.icon}</div>
<div className="sidebarText"><SidebarLabel>{item.title}</SidebarLabel></div>
</div>
<div>
{item.subNav && subnav
? item.iconOpened
: item.subNav
? item.iconClosed
: null}
</div>
</SidebarLink>
{subnav &&
item.subNav.map((item, index) => {
return (
<DropdownLink to={item.path} key={index}>
{item.icon}
<SidebarLabel>{item.title}</SidebarLabel>
</DropdownLink>
);
})}
</>
);
};
export default SubMenu;
Anyone got any idea please on how to fix this?
Even though you're asking about remembering which item was clicked, I think what you actually want is that the link corresponding to the current page be highlighted as active.
If you're using react-router v6, you should use NavLink instead of Link (docs).
A <NavLink> is a special kind of <Link> that knows whether or not it is "active".
By default, an active class is added to a <NavLink> component when it is active.
You should update the imported component and remove the activeClassName.
const SidebarLink = styled(NavLink)`
// ...
&.active {
color: red;
}
`
// ...
<SidebarLink to={item.path} onClick={item.subNav && showSubnav} exact>
...
</SidebarLink>
If you're using react-router v5, then you should also use NavLink but you have to pass the activeClassName, like you do in your example. In this case you simply need to substitute Link for NavLink.
Also note that you nested CSS syntax is incorrect. It is applied to the children of SidebarLink, not on SidebarLink itself. You'd want to replace .selected { color: red; } with &.selected { color: red }.

How can I center text in a button component using styled-components?

I have made a button component using styled-components like below.
And I am using this button component in another component, even made a parent component to the button component, hoping that if the parent component has "text-align: center" attribute, it'd center texts in my button, which turned out not... maybe I did not do it right?
Below is my code for Button.js
import React from "react";
import styled, { css } from "styled-components";
const Container = styled.div`
text-align: center;
`;
const colorStyles = css`
${(props) =>
props.color === "blue" &&
css`
background: #588ced;
color: #ffffff;
&:hover {
background: #3866bc;
}
`}
${(props) =>
props.color === "gray" &&
css`
background: #eeeef2;
color: #65636a;
&:hover {
background: #dbdadf;
}
`}
`;
const sizeStyles = css`
${(props) =>
props.size === "normal" &&
css`
width: 181px;
height: 48px;
`}
${(props) =>
props.size === "small" &&
css`
width: 100px;
height: 40px;
`}
`;
const shapeStyles = css`
${(props) =>
props.shape === "round" &&
css`
border-radius: 50px;
`}
${(props) =>
props.shape === "squared" &&
css`
border-radius: 10px;
`}
`;
const StyledButton = styled.button`
/* common styles */
display: flex;
outline: none;
border: none;
font-family: Roboto;
font-style: normal;
font-weight: bold;
font-size: 16px;
line-height: 19px;
cursor: pointer;
align-items: center;
text-align: center;
/* sizes */
${sizeStyles}
/* colors */
${colorStyles}
/* shapes */
${shapeStyles}
/* etc */
// & + & {
// margin-left: 1rem;
// }
`;
function Button({ children, color, size, shape, ...rest }) {
return (
<Container>
<div>
<StyledButton color={color} size={size} shape={shape} {...rest}>
{children}
</StyledButton>
</div>
</Container>
);
}
export default Button;
AND this is a part from the other component where the button component is used.
import styles from "./Page.module.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import Button from "../button/Button";
export default function Page({ data, setModalVisibleState }) {
const addButtonHandler = () => {
setModalVisibleState(true);
};
return (
<div className={styles.container}>
<div className={styles.titleBox}>
<FontAwesomeIcon icon={faGraduationCap} />
<p>{data.title}</p>
<div className={styles.buttonWrap}>
<Button size="normal" shape="squared" color="blue" onClick={addButtonHandler}>{data.button}</Button>
</div>
</div>
//...and more...
And under "./Page.module.css" I have done this.
.buttonWrap {
display: flex;
text-align: center;
align-items: center;
}
This is how my buttons look right now. Before I used text-align and align-items attributes the text was located on the upper left side of the button. Is there an way to center texts in the button?
I am wondering if the purple box on the right has anything to do with centering the text..
Thank you very much in advance for reading and kindly answering my question. :)
Just add: justify-content: center; Aligning Items in a Flex Container
To center our box we use the align-items property to align our item on the cross axis, which in this case is the block axis running vertically. We use justify-content to align the item on the main axis, which in this case the inline axis running horizontally.
DEMO
button{
display: flex;
outline: none;
border: none;
font-family: Roboto;
font-style: normal;
font-weight: bold;
font-size: 16px;
line-height: 19px;
cursor: pointer;
align-items: center;
text-align: center;
border-radius: 50px;
background: #588ced;
color: #ffffff;
width:189px;
height:48px;
}
<button>button</button>
<button style="justify-content: center;">button</button>

typescript props type for styled input component

i am new to TS and I have been asked to move existing JS code base to ts. I have styled component which looks like this (style.js)
import styled from "styled-components";
export const Container = styled.div`
${({ flex }) => flex && `flex: ${flex};`}
${({ flex }) => flex && `display: flex;`}
flex-direction: column;
`;
export const Label = styled.label`
display: inline-block;
color: #95aac9;
font-size: 12px;
`;
export const DefaultInput = styled.input`
border: 1px solid #dfe0eb;
background-color: transparent;
padding: 10px 12px;
border-radius: 4px;
height: 35px;
color: #888888;
font-weight: 500;
&:focus {
outline: none;
}
`;
export const GrayInput = styled.input`
border: none;
background-color: #ebf2fb;
border: 1px solid #e1e9f5;
border-radius: 5px;
padding: 5px 10px;
&:focus {
outline: none;
}
`;
I was writting types for the file where I am importing this
import React from "react";
import Label from "components/atoms/Label";
import { DefaultInput, GrayInput, NormalInput, Container } from "./styles";
export default function Input({flex, theme, ...props}:{flex:string, theme}) {
return (
<Container flex={props.flex}>
{props.label && <Label>{props.label}</Label>}
{(!props.theme || props.theme === "light") && <DefaultInput {...props} />}
{props.theme === "gray" && <GrayInput {...props} />}
{props.theme === "normal" && <NormalInput {...props} />}
</Container>
);
}
but I can't figure the type for the {...props] in export default function Input({flex, theme, ...props}:{flex:string, theme}) { and how to write it
I think this should do the work:
export default function Input({flex, theme, ...props}:{flex:string; theme: string; [rest: string]: any })
You should also use flex and theme variables directly instead of props.flex and props.theme, because you already destructured them from the passed object (props) and therefore they are not available(defined) there anymore.

React styled-component don't pass props

What I did:
I'm passing some props to functional component Stat.jsx.
What I expected:
I need to pass some background gradient color codes as a string type prop to the Stat.jsx component to make custom color elements.
What happened:
Props aren't passing to the Stat.jsx, also props object is empty.
Stat.jsx
import React from 'react';
import styled from 'styled-components';
const Stat = styled.div`
display: flex;
align-items: center;
justify-content: center;
padding: 0 2.5em;
width: auto;
height: 2.5em;
border-radius: 0.5em;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.2);
background: linear-gradient(160deg, ${(props) => console.log(props) });
font-size: 1.8em;
font-family: Rubik-Medium;
color: #fff;
`;
// console.log(props) is returning object: { children: "1000", theme: {} }
export default ({ value }) => <Stat>{value}</Stat>;
Stats.jsx
import React from 'react';
import Stat from './Stat';
import styled from 'styled-components';
const Stats = styled.div`
display: flex;
`;
export default () => (
<div>
<Stats>
<Stat value="1000" background="#F4D03F, #16A085" />
</Stats>
</div>
);
Quick Fix
Because you don't pass the background prop to the actual Stat component:
export default (props) => <Stat {...props}>{props.value}</Stat>;
Explanation
A better way to illustrate the issue is by renaming your components:
import React from 'react';
import styled from 'styled-components';
const StyledStat = styled.div`
display: flex;
align-items: center;
justify-content: center;
padding: 0 2.5em;
width: auto;
height: 2.5em;
border-radius: 0.5em;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.2);
background: linear-gradient(160deg, ${(props) => console.log(props) });
font-size: 1.8em;
font-family: Rubik-Medium;
color: #fff;
`;
export default function Stat(props){
const { value } = props;
return (
<StyledStat {...props}>
{value}
</StyledStat>;
};
Styled components props comes from the ThemeProvider usually, this is why you see a theme props while console.logging inside your styled.div
Usually in App.js you have something like that:
// src/App.jsx
import React from 'react'
import { ThemeProvider } from 'styled-components';
const theme: {
colors: {
primary: blue,
}
}
const App = () => (
<ThemeProvider theme={theme}>
<Stat />
</ThemeProvider>
)
export default App;
you can access these attributes with
${(props) => props.theme.colors.primary }
because styled-components provides its theme props to every StyledComponents (there is a Context Provider/consumer thing behind)
import React from 'react';
import styled from 'styled-components';
const Stat = styled.div`
display: flex;
align-items: center;
justify-content: center;
padding: 0 2.5em;
width: auto;
height: 2.5em;
border-radius: 0.5em;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.2);
background: linear-gradient(160deg, ${(props) => props.theme.colors.primary} });
font-size: 1.8em;
font-family: Rubik-Medium;
color: #fff;
`;

Styling a Router Link with styled-components

What is the best way to style the Link using the styled-components library in the code that follows.
I can find lots of examples to work with anchor tag but none to work with react-router link.
Am I going about the correct way.
import React from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";
const Nav = ({ className }) => {
return (
<div className={className}>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</div>
);
};
export default styled(Nav)`
color: white;
text-align: left;
background: teal;
width: 100%;
ul {
color: red;
display: flex;
flex-direction: row;
border: 1px solid green;
list-style: none;
li {
padding: 15px 15px;
border: 2px solid purple;
}
}
`;
Thanks
Joseph Shanahan
Yes thanks for your help. A slimmed down version of what I will implement is as follows.
It also has the advantage in that I did not have to implement an unordered list.
import React from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";
const Nav = ({ className }) => {
return (
<div className={className}>
<NavLink to="/">Home</NavLink>
<NavLink to="/about">About</NavLink>
</div>
);
};
const NavLink = styled(Link)`
padding: 20px;
color: white;
text-decoration: none;
&:hover {
color: red;
background: blue;
}
`;
export default styled(Nav)`
color: white;
width: 100%;
display: flex;
justify-content: flex-end;
`;
Thanks Joseph Shanahan
You are in the right way, but little wrong, instead of using ul you just pass the component reference.
export default styled(Nav)`
color: white;
text-align: left;
background: teal;
width: 100%;
${Link} {
/* style for Link Component */
}
`;
Check this answer, it's very familiar.
react-router link translates to after all in <a> tags so style them in the same way you would style an <a> tag
so let's say, you need to change their color to red then:
ul {
color: red;
}
won't work, you will need to do:
ul a {
color: red;
}
If you just want to style the Link component, then the usual way in my experience is to create a styled component like so:
const NavLink = styled(Link)`
/* Link styles */
`
And then just render it like <NavLink>Home</NavLink>.
This also makes it easy to reuse this styled component.

Categories