-
-
Save bluetechy/f3c371349a5a1b1150edc2f4139e00b6 to your computer and use it in GitHub Desktop.
Dynamically add and remove tabs in Material UI (Browser tabs feature)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* No licenses, use as pleased. | |
* The code here uses React Class components (ES6 classes). | |
* Ken Nguyen has made a hooks version of this! Please find that here: https://codesandbox.io/s/addanddelete-tabs-mui-bo7tw | |
* Cheers! | |
*/ | |
import React, { Component } from "react"; | |
import { | |
withStyles, | |
AppBar, | |
Tabs, | |
Tab, | |
Grid, | |
Button | |
} from "@material-ui/core"; | |
import Add from "@material-ui/icons/Add"; | |
import Close from "@material-ui/icons/Close"; | |
import cloneDeep from "lodash/cloneDeep"; | |
const styles = theme => ({ | |
root: { | |
flexGrow: 1, | |
marginTop:"60px", | |
width: "100%", | |
backgroundColor: theme.palette.background.paper | |
}, | |
appBar:{ | |
color:"inherit", | |
backgroundColor: theme.palette.background.paper | |
} | |
}); | |
class CustomTabs extends Component { | |
constructor(...args){ | |
super(...args); | |
this.state = { | |
value: 0, | |
tabList : [{ | |
key:0, | |
id:0, | |
}] | |
}; | |
} | |
addTab = () => { | |
this.setState((state,props)=>{ | |
let tabList = cloneDeep(state.tabList); | |
let id = tabList[tabList.length-1].id+1; | |
tabList.push({ | |
key:id, | |
id:id, | |
}); | |
return { | |
tabList, | |
} | |
}) | |
} | |
deleteTab = (e) => { | |
// prevent MaterialUI from switching tabs | |
e.stopPropagation(); | |
// Cases: | |
// Case 1: Single tab. | |
// Case 2: Tab on which it's pressed to delete. | |
// Case 3: Tab on which it's pressed but it's the first tab | |
// Case 4: Rest all cases. | |
// Also cleanup data pertaining to tab. | |
// Case 1: | |
if(this.state.tabList.length === 1){ | |
return; // If you want all tabs to be deleted, then don't check for this case. | |
} | |
// Case 2,3,4: | |
let tabID = parseInt(e.target.id); | |
let tabIDIndex = 0; | |
let tabList = this.state.tabList.filter((value,index)=>{ | |
if(value.id === tabID){ | |
tabIDIndex = index; | |
} | |
return value.id !== tabID; | |
}); | |
this.setState((state,props)=>{ | |
let curValue = parseInt(state.value); | |
if(curValue === tabID){ | |
// Case 3: | |
if(tabIDIndex === 0){ | |
curValue = state.tabList[tabIDIndex+1].id | |
} | |
// Case 2: | |
else{ | |
curValue = state.tabList[tabIDIndex-1].id | |
} | |
} | |
return { | |
value:curValue | |
} | |
},()=>{ | |
this.setState({ | |
tabList:tabList | |
}) | |
}); | |
} | |
handleTabChange = (event, value) => { | |
this.setState({ value }); | |
} | |
render() { | |
const { classes } = this.props; | |
const { value } = this.state; | |
// console.log(this.state); | |
return ( | |
<AppBar position="static" className={classes.appBar}> | |
<Grid | |
container | |
alignItems="center" | |
justify="center" | |
> | |
<Grid | |
item | |
xl={11} | |
lg={11} | |
md={11} | |
sm={11} | |
xs={11} | |
> | |
<Tabs | |
value={value} | |
onChange={this.handleTabChange} | |
indicatorColor="primary" | |
textColor="primary" | |
variant="scrollable" | |
scrollButtons="auto" | |
> | |
{ | |
this.state.tabList.map((tab)=>( | |
<Tab | |
key={tab.key.toString()} | |
value={tab.id} | |
label={"Node "+tab.id} | |
icon={ | |
<Close | |
id={tab.id} | |
onClick={ | |
this.deleteTab | |
} | |
/> | |
} | |
className="mytab" | |
/> | |
)) | |
} | |
</Tabs> | |
</Grid> | |
<Grid | |
item | |
xl={1} | |
lg={1} | |
md={1} | |
sm={1} | |
xs={1} | |
> | |
<Button | |
variant="outlined" | |
onClick={this.addTab} | |
> | |
<Add/> | |
</Button> | |
</Grid> | |
</Grid> | |
</AppBar> | |
); | |
} | |
} | |
export default withStyles(styles)(CustomTabs); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment