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
Related
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.
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>
I am working on a React project, and I divided some of the pages into tabs using the MUI Tab component, so I can have multiple components in one page and render each component accordingly, so I have created the Tabs component. However, I can only see one first index tab.
Reusable tab MUI component:
export default function useTabs(props) {
const { children, value, index, label, ...other } = props;
const [selectedValue, setSelectedValue] = React.useState(0);
const handleChange = (event, newValue) => {
setSelectedValue(newValue);
};
return (
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs
value={selectedValue}
onChange={handleChange}
className={classes.tab}
textColor="primary"
indicatorColor="primary"
>
<Tab label={label} {...a11yProps(0)} className={classes.tabText} />
{/* <Tab className={classes.tabText} label={label} {...a11yProps(1)} /> */}
</Tabs>
</Box>
<TabPanel value={selectedValue} index={index}>
{children} // Rendering tab children here, but getting only the first component
</TabPanel>
</Box>
);
}
Here is how I am using it:
// Import the reusable component
import Tab from "../common/Tabs";
export default function JobsRecruitments() {
return (
<>
<Tab label="tab name" index={0}>
<MyComponent />
</Tab>
</>
)
}
I don't think it's a good idea to use children if you want reusable tabs. That's because your tabs have to be consistent: if you have 3 child nodes, you should also have 3 tab labels. If you're using children, you can easily lose track of that.
However, if you want to make a reusable tab component, I would suggest passing an array of objects containing the tab label and Component as a property to your custom Tab component. Here's an example of what I mean:
export default function BasicTabs({ tabs }) {
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"
>
{tabs.map(({ label }, i) => (
<Tab label={label} key={i} />
))}
</Tabs>
</Box>
{tabs.map(({ Component }, i) => (
<TabPanel value={value} index={i} key={i}>
{Component}
</TabPanel>
))}
</Box>
);
}
And then you can use this component like this:
import Tabs from "./MyTabs";
const tabs = [
{
label: "Tab 1",
Component: <div>Hello, I am tab 1</div>
},
{
label: "Tab 2",
Component: <div>Hello, I am tab 2</div>
},
{
label: "Tab 3",
Component: (
<div>
<h1>Tab with heading</h1>
<p>Hello I am a tab with a heading</p>
</div>
)
}
];
export default function App() {
return (
<div>
<Tabs tabs={tabs} />
</div>
);
}
Here's the Codesandbox with the full example
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
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>