CSS Curved Tabs like Google Chrome - css

I'm using Material UI Tabs in React to implement curved tabs (imagine like ones shown in Google Chrome). The structure must be such that the parent can give a bottom border which should stretch across the entire row making this bottom-border appear on tabs as well as on some other content on right. The selected (or active) tab, however, must remove the bottom border applied on it by its parent.
Expected Result:
Current Result:
The border from parent gets applied over the selected tab too, which is not what I want.
Here's the CodeSandbox link for my code.
Approach Taken:
I tried creating an ::after pseudo-element positioned absolute for selected tab with higher z-index. This pseudo-element creates a white-colored horizontal line and patches it over the bottom border applied by parent to overlap parent's border. However, I could not make it work. There were a couple of other CSS changes I applied; none seemed to move the parent's border. Any help to correct the existing approach I'm taking or suggesting a new approach to get the desired result is appreciated.
(Please note that I want to keep using Material UI Tabs as the base.)
On a side note, could anyone help why there's also some lag when selecting a tab?

Here is a way you can get your desired effect. Remove the parent bottom border, add a new css selector so you can give tabs that arent .MuiSelected a bottom border, then give the someother content div a bottom border so the grey line continues for the full length of the page (the grey is a slightly different shade cause of mui, but you could specifically set it to the right color):
https://codesandbox.io/s/curvy-tabs-using-material-ui-forked-lx57sw?file=/src/App.js
subtabs
import styled from "#emotion/styled";
import MuiTabs from "#material-ui/core/Tabs";
export const StyledSubTabs = styled(MuiTabs)`
.MuiButtonBase-root.MuiTab-root {
background: white;
border-radius: 8px 8px 0 0;
:hover {
background: pink;
}
}
.MuiButtonBase-root.MuiTab-root.Mui-selected {
border-top: 3px solid gray;
border-left: 3px solid gray;
border-right: 3px solid gray;
border-bottom: none; /* not working */
z-index: 10;
:hover {
background-color: pink;
}
}
//
//added this
//
.MuiButtonBase-root.MuiTab-root {
border-bottom: 3px solid gray;
z-index: 10;
:hover {
background-color: pink;
}
}
.MuiTabs-indicator {
display: none;
}
`;
app.js
import React, { useState } from "react";
import Tab from "#material-ui/core/Tab";
import { StyledSubTabs } from "./SubTabs.styles";
const App = () => {
const [index, setIndex] = useState(0);
const handleChange = (event, newIndex) => {
console.log("SubTab - index", newIndex, event);
setIndex(newIndex);
};
const parentStyles = {
// remove this ----> borderBottom: "3px solid gray",
display: "flex",
justifyContent: "space-between",
alignItems: "center"
};
return (
<div style={parentStyles}>
<StyledSubTabs value={index} onChange={handleChange}>
<Tab label="Tab 1" />
<Tab label="Tab 2" />
<Tab label="Tab 3" />
</StyledSubTabs>
<div
//added this
style={{
borderBottom: "3px solid gray",
height: 45,
flexGrow: 1
}}
>
Some Other Content
</div>
</div>
);
};
export default App;

Related

Styling textarea in MUI using Styled Components

I am trying to change the border color on focus on a textarea component in MUI. I am using styled components:
import "./styles.css";
import { styled } from "#mui/material/styles";
const TextAreaStyle = styled("textarea")(({ theme }) => ({
border: `2px solid #F9FAFB`,
width: "100%",
flexGrow: 1,
boxSizing: "border-box",
borderRadius: 3,
backgroundColor: "#f8f8f8",
// font-size: 16px;
resize: "none",
"&:focus": {
border: `2px solid #454F5B`
},
"&:hover": {
border: `2px solid #F4F6F8`
}
}));
export default function App() {
return (
<div className="App">
<TextAreaStyle />
</div>
);
}
Sandbox: https://codesandbox.io/s/youthful-sammet-qhsfqf?file=/src/App.js
However, while the hover works, the focus does not work. The border color still looks like the default color. Can someone point me in the right direction?
Your code is working, is just that the color you have is too light and similar to the default color. Check it out:
https://codesandbox.io/s/cranky-leakey-mtfutl
EDIT: Updated the sandbox to remove the outline from Chrome
To remove that outline that some browsers have you just have to do
outline: "none"
SECOND EDIT:
for showing the focus border while on hover, just change the order of the styles, with focus last:
"&:hover": {
border: `2px solid #FF0000`
},
"&:focus": {
border: `2px solid #0FF00F`,
outline: "none"
}
I updated the sandbox to reflect that

BorderWidth set to 2px but not showed on page

I'm working on an app with react, material-ui. I'm trying to add border to a div but failed. Following is my code
<div className={classes.search}>
...
</div>
search: {
...
borderWidth: '2px',
borderColor: theme.palette.primary.main,
},
I check in chrome and it shows my border parameter is identified by chrome as 2px, but chrome use 0px instead of 2px as final border width. Any ideas on how it happened?
Seems like you missed to set borderStyle.
You can set the border style with Material-UI theme like the following.
const useStyles = makeStyles((theme) => ({
search: {
border: `2px solid ${theme.palette.primary.main}`
}
});

React.js & styled-components - Styled Input with (the illusion of ) Element inside it

so what i'm trying to do is to create an styled input that seem to have a fixed text (div / children / etc...) inside it.
one image can be self explenatory so this is how it looks like right now:
it seems simple, and the basic idea i quite is:
i got some Wrapper component that has 2 children - the input itself & some element.
like so:
const Input = (props: InputProps) => {
return (
<Wrapper>
<InputStyled {...props} />
<InnerElement>cm</InnerElement>
</Wrapper>
);
};
export default Input;
So where is the problem?
The problem is when i'm trying to set width to this component.
It destroys everything.
is looks like so:
so the wrapper should get a width prop and keep the input and the text element inside of it.
here is a codesandbox i created:
https://codesandbox.io/s/reactjs-input-with-element-inside-forked-2kr6s?file=/src/App.tsx:0-1795
it'll be nice if someone understand what i'm doing wrong.
here are some files:
Input.tsx
import React, { InputHTMLAttributes, CSSProperties } from "react";
import styled from "styled-components";
export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
style?: CSSProperties;
label?: string;
value: string | number;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
text?: string;
isDisabled?: boolean;
hasError?: boolean;
errorLabel?: string | Function;
placeholder?: string;
width?: string;
}
const defaultProps: InputProps = {
text: "",
onChange: () => null,
value: ""
};
const Wrapper = styled.div<Partial<InputProps>>`
outline: 1px dashed red;
box-sizing: border-box;
justify-self: flex-start; // This is what prevent the child item strech inside grid column
border: 2px solid lightblue;
background: lightblue;
border-radius: 8px;
display: inline-flex;
align-items: center;
max-width: 100%;
width: ${({ width }) => width};
`;
const InputStyled = styled.input<Partial<InputProps>>`
box-sizing: border-box;
flex: 1;
outline: 1px dashed blue;
padding: 8px;
border: none;
border-radius: 8px;
max-width: 100%;
:focus {
outline: none;
}
`;
const InnerElement = styled.div`
outline: 1px dashed green;
box-sizing: border-box;
${({ children }) =>
children &&
`
padding: 0 8px;
font-size: 13px;
`};
`;
const Input = (props: InputProps) => {
return (
<Wrapper width={props.width}>
<InputStyled {...props} />
<InnerElement>{props.text}</InnerElement>
</Wrapper>
);
};
Input.defaultProps = defaultProps;
export default Input;
App.tsx
import * as React from "react";
import "./styles.css";
import Input from "./Input";
import styled from "styled-components";
const ContainerGrid = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 50px;
`;
export default function App() {
const [value, setValue] = React.useState("");
const handleChange = (e: any) => {
setValue(e.target.value);
};
const renderInputWithElement = () => {
return (
<ContainerGrid>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"60px"} // Play with this
text="inch"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"110px"} // Play with this
text="cm"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"200px"} // Play with this
text="mm"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"100%"} // Play with this
text="El"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"100%"} // Play with this
/>
</ContainerGrid>
);
};
return (
<div className="App">
<h1>StyledCode</h1>
<h3>Input with an element inside</h3>
<p>
This is kind of an illusion since input cannot have child element inside
of it really.
</p>
<hr style={{ marginBottom: "32px" }} />
{renderInputWithElement()}
</div>
);
}
I Fixed it for you:
https://codesandbox.io/s/reactjs-input-with-element-inside-forked-h2het
First problem was that your were setting the same width to Wrapper and to InputStyled (by passing ...props) Then things get messy. Obviously, both parent and children which has some other element next to it can't have same width. InputStyled's won't be rendered with width you give it, but lesser, as it's being stretched to left by InnerElement.
If you need to pass it all the props, including the width, than you can just remove that width prop by setting width to unset
<InputStyled {...props} width="unset" />
However, there was another issue with padding interfering with width calculation. See answer to another question:
According to the CSS basic box model, an element's width and height
are applied to its content box. Padding falls outside of that content
box and increases the element's overall size.
As a result, if you set an element with padding to 100% width, its
padding will make it wider than 100% of its containing element. In
your context, inputs become wider than their parent.
You can go along with solution there. However, the one simple solution is to use width lesser than your padding, so width: calc(100% - 16px). This does the trick.
So i've found the answer, and its quite simple.
since the browser initializes an input with a width, it cause problems
with the flexbox behavor - the input element can't shrink below its default width and is > forced to overflow the flex container.
So i added min-width: 0 to InputStyled.
thats it.
#justdv thanx for your answer, you right about the width being on the wrong place, i fixed it but the sandbox wasnt updated. i missed that.
thanx anyway for your time :)
here is my fixed sandbox:
https://codesandbox.io/s/reactjs-input-with-element-inside-forked-44h8i?file=/src/Input.tsx
Thanx again for reading.

React component stops working when I add css to it

I have a component that has a state "style" which changes to a random color in my colors array whenever a button is clicked. The state is passed inside a style attribute so that the backgroundColor would become whatever the state is. This is working but whenever I try to add css to the button, it stops working as intended. I have a hunch that it could be due to the position absolute that I used but I have no idea why it's doing that.
All I could do was comment out the CSS to make the button work again but that really doesn't solve my issue.
import React, {Component} from 'react';
import "./Tap.css";
class Tap extends Component{
constructor(props){
super();
this.state={
style: ''
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
const colors = ["#68ad45", "#123456", "#987546", "#ab23c6", "#324517", "#456819"];
let i = Math.floor(Math.random() * 6);
this.setState({
style: colors[i]
});
}
render(){
return(
<div className="Tap" style={{backgroundColor: this.state.style}}>
<button onClick={this.handleClick}>Click Here</button>
</div>
);
}
}
export default Tap;
// ========================== CSS file ==========================
.Tap button{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: none;
outline: none;
padding: 10px;
font-size: 200px;
cursor: pointer;
}
No error messages, just no result coming from the button after it's been styled with the css.
This is because: position: absolute which is added to button,
So Tab div have no height now
One solution: is to div that div fixed height:
.Tap {
height: 50px;
}
See Example 1
But if you noticed that the tab not aligned with button because of absolute position.
Other Solution position the Tab not the button as absolute with some padding:
See example 2
Just do this simple change <button onClick={this.handleClick} style={{backgroundColor: this.state.style}}>Click Here</button>
check sample code - https://stackblitz.com/edit/react-soy8a4

Unable to modify some internal styles of Material UI's <Dialog> component

I'm trying to apply some reasonably simple styles to my <Dialog> component. In this case, I am trying to round the corners with a border radius. Here are some simple inline styles that I'd like to use to override the default <Dialog> styles:
let overrideStyles = {
padding: 0,
margin: 0,
borderRadiusTopLeft: '4px',
borderRadiusTopRight: '4px',
};
<Dialog> provides a wide variety of possibilities for overriding internal styles. These include bodyStyle, contentStyle, style, titleStyle, overlayStyle, and actionsContainerStyle. I decided to try to apply these styles to each one.
<Dialog
bodyStyle={overrideStyles}
contentStyle={overrideStyles}
style={overrideStyles}
titleStyle={overrideStyles}
overlayStyle={overrideStyles}
actionsContainerStyle={overrideStyles}
modal={overrideStyles}
>
<TestPanel/>
</Dialog>
When I render my TestPanel, it ends up looking like this:
Notice the corners, where my border radius has not been applied... I opened up the inspector and noticed the following div:
If I apply the border radius styling to the highlighted div, the dialog will have its corners rounded as expected. Which leads me to my question...
How do I override the styles of Material UI's <Dialog> component to apply rounded corners as my CSS is attempting?
I solved it with paperProps property.
<Dialog PaperProps={{
style: { borderRadius: 2 } }}
> .... </Dialog>
This perfeclty worked for me
You can override styles like below.
const styles = {
root: { }
paper: { borderRadius: 15 }
}
// ...
<Dialog classes={{
root: classes.root,
paper: classes.paper
}}>
</Dialog>
Unfortunately, Material UI isn't supremely style-friendly. In this case, there's no prop you can override to change the border-radius, so we've got to apply our own class:
let headerStyles = {
color: 'white',
textAlign: 'center',
fontSize: 24,
backgroundColor: '#3B8DBC',
padding: 20,
borderTopLeftRadius: 4,
borderTopRightRadius: 4
};
let bodyStyles = {
backgroundColor: 'white',
padding: 10,
height: 200
};
<Dialog className='test'>
<div style={headerStyles}>Testing</div>
<div style={bodyStyles}>5:43pm</div>
</Dialog>
Then style that class, and, yes, the border-radius has to be set on both of the below CSS classes as well as the TestPanel header:
/* Some rules use !important because Material UI sets them by default */
.test > div > div {
background-color: #3B8DBC; /* Same background-color as TestPanel */
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.test > div > div > div {
/* Not overriding the color and border radius here too result in your changes
not being visible. */
background-color: inherit !important;
border-top-left-radius: 4px !important;
border-top-right-radius: 4px !important;
}
.test > div > div > div > div {
/* This div is the topmost padding between the modal content and the edge
of the modal */
padding: 0 !important;
}
This ends up looking like what you want:
screenshot here
Hope this helps!
You can override <Dialog /> styles globally in your application when creating your theme object. The paper key of MuiDialog will let you target the border-radius.
const theme = createMuiTheme({
overrides: {
MuiDialog: {
paper: {
borderTopLeftRadius: '4px',
borderTopRightRadius: '4px'
}
}
}
})
Dialog - CSS api
Material UI Theming
The first answer is not working for me. I tried this and it work perfect for me:
sx={{
"& .MuiDialog-container": {
"& .MuiPaper-root": {
width: "100%",
maxWidth: "740px",
borderRadius: "8px"
}
},
}}

Resources