Horizontal Scroll is not working in material ui tabs? - reactjs

I'm building my react js application from scratch. At some point i have use a dynamic tabs, where the length of tabs may be unable to define. I have find the code of scrollable tabs from material ui. But everything is working fine except the horizontal scroll of tab when it exceeds a particular length.The material ui code is given below.
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import PhoneIcon from '#material-ui/icons/Phone';
import FavoriteIcon from '#material-ui/icons/Favorite';
import PersonPinIcon from '#material-ui/icons/PersonPin';
import HelpIcon from '#material-ui/icons/Help';
import ShoppingBasket from '#material-ui/icons/ShoppingBasket';
import ThumbDown from '#material-ui/icons/ThumbDown';
import ThumbUp from '#material-ui/icons/ThumbUp';
import Typography from '#material-ui/core/Typography';
import Box from '#material-ui/core/Box';
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`scrollable-force-tabpanel-${index}`}
aria-labelledby={`scrollable-force-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `scrollable-force-tab-${index}`,
'aria-controls': `scrollable-force-tabpanel-${index}`,
};
}
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
},
}));
export default function TabsButton() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<AppBar position="static" color="default">
<Tabs
value={value}
onChange={handleChange}
variant="scrollable"
scrollButtons="on"
indicatorColor="primary"
textColor="primary"
aria-label="scrollable force tabs example"
>
<Tab label="Item One" icon={<PhoneIcon />} {...a11yProps(0)} />
<Tab label="Item Two" icon={<FavoriteIcon />} {...a11yProps(1)} />
<Tab label="Item Three" icon={<PersonPinIcon />} {...a11yProps(2)} />
<Tab label="Item Four" icon={<HelpIcon />} {...a11yProps(3)} />
<Tab label="Item Five" icon={<ShoppingBasket />} {...a11yProps(4)} />
<Tab label="Item Six" icon={<ThumbDown />} {...a11yProps(5)} />
<Tab label="Item Seven" icon={<ThumbUp />} {...a11yProps(6)} />
<Tab label="Item Five" icon={<ShoppingBasket />} {...a11yProps(4)} />
<Tab label="Item Six" icon={<ThumbDown />} {...a11yProps(5)} />
<Tab label="Item Seven" icon={<ThumbUp />} {...a11yProps(6)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
Item One
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
<TabPanel value={value} index={3}>
Item Four
</TabPanel>
<TabPanel value={value} index={4}>
Item Five
</TabPanel>
<TabPanel value={value} index={5}>
Item Six
</TabPanel>
<TabPanel value={value} index={6}>
Item Seven
</TabPanel>
<TabPanel value={value} index={4}>
Item Five
</TabPanel>
<TabPanel value={value} index={5}>
Item Six
</TabPanel>
<TabPanel value={value} index={6}>
Item Seven
</TabPanel>
</div>
);
}
Help will be appreciated

Related

React: Using a same component twice in a page removes the data in first component

I have two tabs in my react app with each tab having a spreadsheet.
I have called the same spreadsheet tag in both the tabs. when i enter data in the first tab and move to second tab, the data in the second tab is getting replaced with the default value which i am setting in the useState.
import * as React from 'react';
import PropTypes from 'prop-types';
import Tabs from '#mui/material/Tabs';
import Tab from '#mui/material/Tab';
import Typography from '#mui/material/Typography';
import Box from '#mui/material/Box';
import Spreadsheet from './components/Spreadsheet.js'
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{ p: 3 }}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
};
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
export default function BasicTabs() {
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<Box sx={{ width: '100%' }}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={value} onChange={handleChange} aria-label="basic tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</Box>
<TabPanel value={value} index={0}>
Item One
<div id='div_spreadsheet1'>
<Spreadsheet id="spreadsheet1"> </Spreadsheet>
</div>
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
<div id='div_spreadsheet12'>
<Spreadsheet id="spreadsheet2"> </Spreadsheet>
</div>
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
</Box>
);
}
EDIT:
Adding the Spreadsheet.js code
import Spreadsheet from "react-spreadsheet";
import { useState } from "react";
export default function Sheet(){
const [data, setData] = useState([
[{ value: "" }, { value: "1" }],
]);
return(
<div>
<h4>SpreadSheet</h4>
<Spreadsheet data={data} onChange={setData} />
</div>
)
};
How to restrict this from happening. Please help.

How can I center the scrollable tab?

There are 3 tabs and I could not center them on the screen. How can I center the scrollable tab? As of now, it will only be on the left side of the screen
codesandbox: https://codesandbox.io/s/material-demo-forked-dbcxl?file=/demo.js
Below are the codes:
import * as React from "react";
import Tabs from "#mui/material/Tabs";
import Tab from "#mui/material/Tab";
import Box from "#mui/material/Box";
export default function ScrollableTabsButtonAuto() {
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<Tabs
value={value}
onChange={handleChange}
variant="scrollable"
scrollButtons="auto"
aria-label="scrollable auto tabs example"
centered
>
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
</Tabs>
);
}
It is because the container of the Tabs has the same width as the Tabs.
You should be able to wrap the Tabs component with a Box which has full width.
For example,
<Box display="flex" justifyContent="center" width="100%">
<Tabs ...>
...
</Tabs>
</Box>

How to create custom scroll icon inside the Material-UI scrolling Tabs

I am using Scrollable tabs from Material-UI. How do I change the svg icon of the scroll arrows?
I see there is TabScrollButton component you can use. So do I have to create one for the left and right arrow?
And in Tabs component you can pass a prop ScrollButtonComponent. But how do I have to use it?
I tried below but it isn't working yet:
import Tab from '#material-ui/core/Tab';
import Tabs from '#material-ui/core/Tabs';
import TabScrollButton from '#material-ui/core/TabScrollButton';
import { CloseIcon } from 'app/components/atoms/icons';
const MyCarousel = ({ value }: Props) => {
const selectedItem = value;
const scrollButton = () => {
return (
<div>
<TabScrollButton orientation="horizontal" direction="right">
{CloseIcon}
</TabScrollButton>
</div>
);
};
return (
<div css={styles.root}>
<Tabs
value={value}
indicatorColor="primary"
variant="scrollable"
scrollButtons="auto"
aria-label="scrollable auto tabs example"
ScrollButtonComponent={scrollButton}
>
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
<Tab label="Item 4" />
<Tab label="Item 5" />
<Tab label="Item 6" />
<Tab label="Item 7" />
<Tab label="Item 8" />
<Tab label="Item 9" />
</Tabs>
</div>
);
};
export default MyCarousel;
You're close. TabScrollButton is the default props of ScrollButtonComponent. Unfortunately, TabScrollButton doesn't provide any props to override the back/forward icons. So you have to create one yourself.
This is the definition of TabScrollButton. What you want to do is to copy the definition, remove unnecessary parts and add your own icons instead. Below is an example:
import ButtonBase from "#material-ui/core/ButtonBase";
import ArrowBackIcon from "#material-ui/icons/ArrowBack";
import ArrowForwardIcon from "#material-ui/icons/ArrowForward";
const MyTabScrollButton = forwardRef((props, ref) => {
const { direction, ...other } = props;
return (
<ButtonBase
component="div"
ref={ref}
style={{ opacity: other.disabled ? 0 : 1 }}
{...other}
>
{direction === "left" ? (
<ArrowBackIcon fontSize="small" />
) : (
<ArrowForwardIcon fontSize="small" />
)}
</ButtonBase>
);
});
<Tabs
{...tabsProps}
variant="scrollable"
scrollButtons="auto"
ScrollButtonComponent={MyTabScrollButton}
>
{...}
</Tabs>
Live Demo

Why Active Tab Redirecting to First Tab in React Material

I have successfully redirect the tab depending on the routes. My problem is when I'm on the second and succeeding tabs, when i refresh the browser, the active highlight on the tabs is going back the first tab?
Why is this happening? Pls check my code below
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`scrollable-auto-tabpanel-${index}`}
aria-labelledby={`scrollable-auto-tab-${index}`}
{...other}
>
{value === index && (
<Box pt={4}>
<div>{children}</div>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `scrollable-auto-tab-${index}`,
'aria-controls': `scrollable-auto-tabpanel-${index}`,
};
}
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
maxWidth: 640,
},
}));
export default function Settings() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div>
<AppBar position="static" color="inherit" className={classes.root}>
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
variant="scrollable"
scrollButtons="auto"
aria-label="scrollable auto tabs example"
>
<Tab label="Users" component={Link} to="/users" {...a11yProps(0)} />
<Tab label="Products" component={Link} to="/products" {...a11yProps(1)} />
<Tab label="Sales" component={Link} to="/sales" {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<Users />
</TabPanel>
<TabPanel value={value} index={1}>
<Products />
</TabPanel>
<TabPanel value={value} index={2}>
<Sales />
</TabPanel>
</div>
);
So, you want to render same component at different routes
<BrowserRouter>
<Route path={"/"} exact component={TabComponent} />
<Route path={"/users"} exact component={TabComponent} />
<Route path={"/products"} exact component={TabComponent} />
<Route path={"/sales"} exact component={TabComponent} />
</BrowserRouter>
and you want to keep active tab depending on route path, you can achieve this by checking pathname in useEffect.
useEffect(() => {
const pathname = props.history.location.pathname;
switch (pathname) {
default:
setValue(0);
break;
case "/users":
setValue(0);
break;
case "/products":
setValue(1);
break;
case "/sales":
setValue(2);
break;
}
}, [props.history.location.pathname]);
Here working example: https://codesandbox.io/s/floral-rgb-6o55s?fontsize=14&hidenavigation=1&theme=dark

How to show contents inside a tab?

I am trying to create a form with three tabs.Now the tabs are created and i am able to switch between them but can not figure out how to display contents inside a tab
I have tried writing markup tags like h1 in between but nothing is shown on the output.
export class Stackreact extends Component {
constructor(props) {
super(props);
this.state = { value: '1' }
}
handle_change = (value) => {
this.setState({ value })
}
render() {
return (
<div>
<Tabs value={this.state.value} onChange={(e, v) => { this.handle_change(v) }} indicatorColor="primary"
textColor="primary" centered>
<Tab value='1' label='BASIC DETAILS'><h1>First Tab</h1></Tab>
<Tab value='2' label='CONTACT DETAILS'><h1>Second Tab</h1></Tab>
<Tab value='3' label='MORE DETAILS'><h1>Third tab</h1></Tab>
</Tabs>
</div>
)
}
}
I want the contents of h1 tags to be displayed in their respective tabs. Please help.Also i am new to this language.
After working a lot I have come up with this solution which is working fine.
render() {
let content_array = [<h1>First Tab</h1>, <h1>Second Tab</h1>, <h1>Third Tab</h1>];
return (
<div>
<Tabs value={this.state.value} onChange={(e, v) => { this.handle_change(v) }} indicatorColor="primary"
textColor="primary" centered>
<Tab value='1' label='BASIC DETAILS'></Tab>
<Tab value='2' label='CONTACT DETAILS'></Tab>
<Tab value='3' label='MORE DETAILS'></Tab>
</Tabs>
<Paper>
{content_array[this.state.value - 1]}
</Paper>
</div>
)
}
You can try using TabView and TabPanel from primereact
<TabView>
<TabPanel>
<h1>First Tab</h1>
<TabPanel />
<TabPanel>
<h1>Second Tab</h1>
<TabPanel />
<TabView />
You can research on your own on the props accepted by TabView and TabPanel
you can use components like this:
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
Item One
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
</div>
official link : Tabs
You are trying to see the content but you've defined it in the wrong place, here you have an example of how to use Tabs and Tab, because you need to define the data that you want inside of each Tab outside the Tabs component (Tab in meant to be used as a self-closing tag).
Here is the simplest answer using hooks inspired by the accepted answer.
import { useState } from 'react';
..
const [tabState, setTabState] = useState(1);
...
const handleTabs = (value) => {
setTabState(value);
return;
}
let tabs_array = [<>{variable_with_contents_tab_1}</>, <>{tab_2_contents}</>];
Then in the render, you can provide the tab ui
<Paper className={classes.root}>
<Tabs
value={tabState}
onChange={(event, value) => { handleTabs(value) }}
indicatorColor="primary"
textColor="primary"
centered
>
<Tab value={1} label='Tab1'>
</Tab>
<Tab value={2} label="Tab2" />
</Tabs>
</Paper>
<Paper>
{tabs_array[tabState-1]}
</Paper>

Resources