How to make noWrap work with Breadcrumbs? - css

I'm trying to make the MUI component Breadcrumbs responsive:
When the Breadcrumbs component takes all of its space, its items shrink using ellipsis like any Typography component with noWrap prop set.
I know it has itemsBeforeCollapse, itemsAfterCollapse and maxItems props but these props are about item number compared to viewport size, not about each item width.
I tried to set the noWrap property to Typography and Link components (as it extends Typography props), but the ellipsis does not show up and the Link or Typography component does not shrink.
<Breadcrumbs>
{links.map((link, i) =>
i !== links.length - 1 ? (
<Link
key={i}
underline={'hover'}
noWrap
>
{link}
</Link>
) : (
<Typography noWrap key={i}>
{link}
</Typography>
),
)}
</Breadcrumbs>
You can reproduce the issue on this codeSandbox:

If I understand you correctly, the problem is that the noWrap style is not affecting the right element.
Why?
noWrap affect elements that its width limited either explicit (e.g. width: 100px) or implicit (by parent's width).
In your case, the Link and the Typography's width is not limited.
What can you do?
Breadcrumbs renders ol with display: flex. In order to force the children (li) to stand a line (and take a third in your case) you should give it flex: 1. From this point, you can give the li the ellipsis styles.
The last part, how to give the li these styles? There are some ways as described at the css section.
I would take the styled approach and this is how it looks
import * as React from "react";
import Typography from "#mui/material/Typography";
import Breadcrumbs from "#mui/material/Breadcrumbs";
import Link from "#mui/material/Link";
import { styled } from "#mui/material/styles";
const StyledBreadcrumbs = styled(Breadcrumbs)`
.MuiBreadcrumbs-li {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
}
`;
export default function BasicBreadcrumbs() {
const links = [
"this is a waaaaaaaaaaaaay too long link",
"and another link that can be long too",
"this is the last link and guess what? It's waaaaaaaaaaaaaaaaaaayyy more longer"
];
return (
<StyledBreadcrumbs>
{links.map((link, i) =>
i !== links.length - 1 ? (
<Link key={i} underline={"hover"}>
{link}
</Link>
) : (
<Typography key={i}>
{link}
</Typography>
)
)}
</StyledBreadcrumbs>
);
}
https://codesandbox.io/s/basicbreadcrumbs-material-demo-forked-y1bbo?file=/demo.js

Related

How do I make material ui container have full width and height?

I am trying to wrap a page in a React project in a material UI container but it squeezes in all my content with these weird margins. Here is what it looks like:
But I want it to look like this with full width:
Haven't been able to find any other resources explaining how to change the width of the container. Does anyone have any workarounds? I tried adjusting the width of the container to be 100vw but it was unresponsive to my CSS. Here is my code:
////BUY PAGE
import React from 'react';
import Container from '#mui/material/Container';
import AppBar from '../../components/AppBar/AppBar';
import Footer from '../../components/Footer/Footer';
import './Buy.css';
const Buy = () => {
return (
<Container>
<AppBar />
<Footer />
</Container>
);
};
export default Buy;
////CSS
.buy-container {
overflow-y: hidden;
width: 100vw;
}
You should be able to get the results you're looking for by setting the maxWidth property of Container to false e.g:
<Container maxWidth={false}>
<AppBar />
<Footer />
</Container>
Edit:
The maxWidth property determines the max-width of the container. The container width grows with the size of the screen. By setting it to false you can disable the maxWidth property.
https://mui.com/api/container/
You will need to add maxWidth={false} and disableGutters properties to the <Container/> component. Additionally, you should include the <CssBaseline/> component to reset the browser's CSS.
Example:
<>
<CssBaseline />
<Container maxWidth={false} disableGutters>
{children}
</Container>
</>
Container API
Name
Type
Default
Description
maxWidth
'xs', 'sm', 'md', 'lg', 'xl', false, string
Determine the max-width of the container. The container width grows with the size of the screen. Set to false to disable maxWidth.
disableGutters
bool
false
If true, the left and right padding is removed.
You should avoid to set the custom container width until changing the breakpoints.
Otherwise, you can use a custom div element or Box component.
// makeStyles
const useStyles = makeStyles(() => ({
root: {
height: '100%',
overflow: 'hidden',
width: '100%'
},
}));
// styled
const LayoutContainer = styled('div')(() => ({
height: '100%',
overflow: 'hidden',
width: '100%'
}));
I'd take a look at global css variables to overwrite the standard (see here):
The material docs suggest this way or using styling overrides which may be another option for you.
.MuiContainer-root {
width: 100vw;
padding-left: 0;
padding-right: 0;
}
FYI - I got the global css name from the Container portion of the docs under "root", in case you've not seen it.
I would use the <Container> within <Box>/<Appbar> that has the background color e.g:
<Box sx={{ bgcolor: 'black'}}>
<Container>
My content
</Container>
</Box>
minHeight: '100%' worked for me in that kind of situation

Using Prismjs for syntax highlighted code blocks is breaking layout on mobile - <pre> element wont take dynamic width

I'm using Prismjs alongside Mdx for a code-related blog. I'm using it to show code blocks in a manner consistent with other blogs.
I'm running into an issue where the rendered code blocks (inside a <pre> element are too wide on my mobile layout. For now I am content to have things scroll on the horizontal axis. I'm 99% certain that the <pre> elements are what's breaking the layout because when I comment them out of the blog post, the layout works as expected.
Specifically, I'm using a package called prism-react-renderer (alongside Gatsby), and the code I have for the CodeBlock element (that handles the syntax highlighting) is more or less verbatim from the documentation for prism-react-renderer, but is included here for convenience:
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
import theme from 'prism-react-renderer/themes/nightOwl'
const CodeBlock = (props) => {
const className = props.children.props.className || ''
const matches = className.match(/language-(?<lang>.*)/)
return (
<Highlight {...defaultProps} code={props.children.props.children.trim()} language={
matches && matches.groups && matches.groups.lang
? matches.groups.lang
: ''
}
theme={theme}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={{ ...style }}>
<code>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
))}
</code>
</pre>
)}
</Highlight>
)
}
export default CodeBlock
This is the component used in the blog post template that handles rendering the .mdx files into HTML:
import React from 'react'
import { Link, graphql } from 'gatsby'
import { MDXRenderer } from 'gatsby-plugin-mdx'
import { MDXProvider } from '#mdx-js/react'
import Layout from '../components/layout'
import CodeBlock from '../components/code-block'
const components = {
pre: CodeBlock
}
const BlogPostTemplate = ({ data, pageContext, location }) => {
const post = data.mdx
const { previous, next } = pageContext
return (
<Layout>
*** Removed irrelevant component ***
<MDXProvider components={components}>
<div className='blog-post-wrapper'>
<article className='blog-post-content'>
<header>
<h1>
{post.frontmatter.title}
</h1>
<time dateTime={post.frontmatter.date}>
{post.frontmatter.date}
</time>
</header>
<MDXRenderer>{post.body}</MDXRenderer>
</article>
<footer className='blog-post-footer'>
*** Removed irrelevant components ***
</footer>
</div>
</MDXProvider>
</Layout>
)
}
export default BlogPostTemplate
I have tried a few different things: flex shrink, applying overflow-x: scroll and overflow-x: auto to both the <pre> element and its parents. When I apply a fixed width to the <pre> element and overflow-x: scroll I can get the behavior I want but I'd like to not have to use a fixed width on this if possible. The .css I have looks like this, including some obviously ineffectual styles:
.blog-post-wrapper {
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-x: scroll;
}
.blog-post-content {
flex-grow: 1;
margin-bottom: 2rem;
width: 100%;
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-x: scroll;
}
.blog-post-content .prism-code {
padding: 20px;
border: 3px solid red;
flex-shrink: 1;
overflow-y: scroll;
overflow-x: scroll;
}
I'll attach images of the way the <pre> element is rendering presently, in inspector:
And this is how it looks if I set a fixed width (in inspector):
It's probably too late, but I had the same issue and I was able to fix it by
Adding max-width css property to the main layout. The value should be equal to window.screen.width. I had to use the following hack to be able to get the screen size:
const [windowWidth, setWindowWidth] = useState(width)
useEffect(() => {
setWindowWidth(window.screen.width)
}, [])
Adding overflow: scroll to the pre in the CodeBlock
Not ideal, but I found this combination of CSS properties working together:
pre code {
display: inline-block;
width: 80vw;
overflow-x: auto;
}

Styled components, two layers of className - How would I apply style in component declaration?

I have created a Container component with component styles in next.js.
When I declare use of this container component throughout my site, I would like to add a className to it and subjectively style it depending on the context of its use.
Here is an example of my Container component:
const Container = (props) => (
<>
<div className="container">
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
So, I want to give it a maximum width of 1200px, and centre it with auto margins. No problem, I have done that.
Now, I am planning to use this component in the header of my site. But in the case of the header, I would like the Container component to be a flexbox:
import Container from './Container'
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
{/* Navigation items */}
</ul>
</nav>
</Container>
</header>
<style jsx>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
When I view the site, I noticed the flexbox style I specified for the Container component in the header is not present.
I was expecting the className to take effect, and allow me to add additional styles.
I believe this has something to do with it thinking that className is not a class name, rather props. But, I want to keep my code dry by creating style inheritance on components.
How could I do this?
Thanks for the help!
This is a job for styled components:
import React from "react";
import styled from "styled-components";
export default function App() {
return (
<>
<Container custom={"header"}>
<h1>Very fancy h1 with flex display</h1>
</Container>
<Container custom={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => (props.custom === "header" ? "flex" : "block")};
/* you can call your prop ^^^^^^ whatever you want,
just change it on the container element too*/
& h1 {
/* you can apply css to children like so */
font-family: ${(props) =>
props.custom === "header"
? '"Courier New", Courier, monospace'
: '"Arial Black", Gadget, sans-serif'};
}
`;
In the above, I've created a custom styled component that receives the custom prop and then conditionally changes the values you are looking to adjust. To make the changes more visible to the eye, I've also styled the font so you can see the immediate difference between the two <Container> elements.
For a solution that is more scalable (e.g., for different themes), use ThemeProvider:
import React from "react";
import styled, { ThemeProvider } from "styled-components";
export default function App() {
return (
<>
<ThemeProvider theme={ContainerHeader}>
<Container>
<h1>Very fancy h1 with flex display</h1>
</Container>
</ThemeProvider>
<Container theme={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => props.theme.display};
& h1 {
font-family: ${(props) => props.theme.h1Font};
}
`;
Container.defaultProps = {
theme: {
display: "block",
h1Font: '"Arial Black", Gadget, sans-serif'
}
};
const ContainerHeader = {
display: "flex",
h1Font: '"Courier New", Courier, monospace'
};
CodeSandbox: https://codesandbox.io/s/stack-conditional-styled-components-vmnpn?file=/src/App.js:0-773
I believe I have found the answer to my own question (I will still leave this question open for a couple more days just in case it can be improved).
In order to pass styles, you can add the "global" flag to the styled JSX and append additional classnames in the component with props.className.
Parent Container component using props.className:
const Container = (props) => (
<>
<div className={`container ${props.className}`}>
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
Then, when you want to use that component, you can add additional styles with the global flag in the <style jsx>:
Container being used and styled even more in the header:
import Container from './Container';
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
<li>Hello</li>
<li>There</li>
</ul>
</nav>
</Container>
</header>
<style jsx global>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
This is not 100% perfect though (but in my opinion it is still pretty good):
The global flag makes your styles global. So other components can use
these styles (I believe)
You need to make sure your components take in props.className to append additional classnames for this global style

Syntax for passing props to ReactMarkdown styled component

I am trying to render some links using ReactMarkdown in a React component, which needs some props to be passed to use special styling.
Links is my styled component which I am applying to paragraph property under renderers in ReactMarkdown. However Links to work I need to pass linkColor={linkcColor} props.
Code: Part of my code is where Container is another styled.div
<Container>
{websites.map((website, index) => (
<div key={'website' + index}>
<ReactMarkdown
source={`[${website.websiteName}](${website.externalUrl})`}
unwrapDisallowed={true}
renderers={{ paragraph: Links, link: Linkrender }}
/>
</div>
))}
</Container>
const Links = styled.div`
color: ${(p) => p.linkColor};
::before {
content: ' ';
white-space: pre;
}
::after {
content: ' /';
white-space: pre;
}
`;
Tried: The following. But it hasn't worked. It loses the source for ReactMarkdown completely and just style is applied to empty div.
<ReactMarkdown
source={`[${website.websiteName}](${website.externalUrl})`}
unwrapDisallowed={true}
renderers={{ paragraph: ({linkColor}) => (
<Links {...linkColor={linkColor}} />), <<<<<<<<<<<<< tried this
link: Linkrender }}
/>
Is the syntax correct? What could be the reason for this not to work? Is it because my styled component is a div which is getting applied on a <p>? Here Linkrender is another styled component custom made which is <a>, and that I can't change.
One way that worked was applying a styled.div as a wrapper and apply a specific styling to the paragrah in ReactMarkdown. Look at the arrows inside the code that explains what to do.
<Container>
<Heading>{`${textStripeHeading}:`}</Heading>
{websites.map((website, index) => (
<Links key={'website' + index} linkColor={linkColor}> <<<<<<<<<<< add <Links> here
<ReactMarkdown
source={`[${website.websiteName}](${website.externalUrl})`}
unwrapDisallowed={true}
renderers={{ paragraph: MarkdownStyle, link: Linkrender }} <<<<<<<<< create new style.p with style and apply to paragraph
/>
</Links>
))}
</Container>
const MarkdownStyle = styled.p`
::before {
content: ' ';
white-space: pre;
}
::after {
content: ' /';
white-space: pre;
}
`;
This is just one solution that worked. I am waiting for others to offer better solution.

I cannot center the Button component in Material-UI using Styled Components

I am quite new to Material UI # next, and I like the fact that it supports Styled Components.
However, I am struggling in aligning the Button component to the center through Styled Components. I only manage to align it by using the styles technique such as this:
const styles = {
container: {
textAlign: "center"
}
};
class Landing extends Component {
render() {
return (
...
<div style={styles.container}>
<Button variant="raised" color="primary">
I am a button
</Button>
</div>
);
}
}
This is something that I like to avoid, and instead use the Styled Components such as:
const Container = styled.div`
text-align: "center";
`;
However, for some reason it is not working although they look exactly identical. Can someone explain whether text-align and textAlign are pointing to the same CSS property?
It works using styled component here is the code
import React from 'react';
import Button from "react-bootstrap/es/Button";
import styled from 'styled-components';
const Container = styled.div`
text-align: center;
`;
class Landing extends React.Component {
render() {
return (
<Container>
<div>
<Button color="primary">
I am a button
</Button>
</div>
</Container>
)};
};
You have to wrap the styled component which you have taken. Here I've taken container and then inside the container, I've added the needed CSS.
For more information and usage about the styled component, you can visit this URL - https://www.styled-components.com/docs/basics
Thanks

Resources