How to change tabs width in material UI - reactjs

I am using material UI tabs v0.20.0 for display content in tabular format. Tabs are taking full width. I have attached screenshot of expected and current output .
Expected output
Current Output
Please let me know a solution for the same.

If you want tabs of fixed width, you need to override the root css class passed to the Tab component, where you have to override both the minWidth and width attributes.
Example:
const Component = ({ classes }) => (
<Tabs value={0}>
<Tab classes={{ root: classes.tab }} label="One" />
<Tab classes={{ root: classes.tab }} label="Two" />
</Tabs>
);
// this is injected as classes prop into the wrapping component
const styles = {
tab: {
minWidth: 200, // a number of your choice
width: 200, // a number of your choice
}
};
export default withStyles(styles)(Component);

The Tabs component does accept a variant prop. One of the following string values are accepted:
fullWidth -> which is OPs current result
standard -> which is the default
scrollable -> adding scrolling functionality via buttons if not all tab items are visible
By now, the OPs expected result should be the default prop (standard).
Official Docs:
Tabs Guide: https://material-ui.com/components/tabs/
Tabs API: https://material-ui.com/api/tabs/

setting the minWidth to 50% does the job
<Tabs value={value} style={{backgroundColor:"#121858",color:"#FFF"}} onChange=
{handleChange} aria-label="simple tabs example" >
<Tab label="Tab One" {...a11yProps(0)} style={{minWidth:"50%"}}/>
<Tab label="Tab Two" {...a11yProps(1)} style={{minWidth:"50%"}}/>
</Tabs>

responsive solution :-
<Tabs variant="fullWidth"> </Tabs>

You're going to have to hardcode a tab width:
const width = 200;
const widthModifier = {
width: `${width}px`,
};
And then apply it to change the tab width:
<Tab label="Item One" style={widthModifier}>
You're also going to have to keep track of the current active tab using onActive and calculate the displacement of the ink bar yourself. Here's a full working example:
import React, { Component } from 'react';
import {Tabs, Tab} from 'material-ui/Tabs';
const styles = {
headline: {
fontSize: 24,
paddingTop: 16,
marginBottom: 12,
fontWeight: 400,
},
};
const width = 200;
const widthModifier = {
width: `${width}px`,
};
class TabWidth extends Component {
constructor(props) {
super(props);
this.state = { selectedIndex: 0 };
}
render() {
const { selectedIndex } = this.state;
// Notice that I have to calculate the left position of the ink bar here for things to look right
return (
<Tabs inkBarStyle={ {left: `${width * selectedIndex}px`, ...widthModifier}}>
<Tab label="Item One" style={widthModifier} onActive={() => this.setState({ selectedIndex: 0 })}>
<div>
<h2 style={styles.headline}>Tab One</h2>
<p>
You can put any sort of HTML or react component in here. It even keeps the component state!
</p>
</div>
</Tab>
<Tab label="Item Two" style={widthModifier} onActive={() => this.setState({ selectedIndex: 1 })}>
<div>
<h2 style={styles.headline}>Tab Two</h2>
<p>
This is another example tab.
</p>
</div>
</Tab>
</Tabs>
);
}
}
export default TabWidth;
But, you really should be using v1 if possible. In material-ui v1, your desired tab behavior is the default right out of the box and will scale based on screen size.

I had this question. You need to just simply add fullWidth to Tabs component link:
<Tabs variant="fullWidth" value={value} onChange={this.handleChange} aria-label="simple tabs example">
<Tab className={classes.root} label={t('login')} />
<Tab className={classes.root} label={t('register')} />
</Tabs>
it worked for me.

Related

Mapping Horizontal divider using Material UI react

I'm working on menu component storybook where i have mapped icon & text , problem is i have horizontal divider in between , how do i Map it with icons & text.From below code i'm getting divider at the bottom of the Menu. I'm trying to achieve as it is in the image. In the storybook i have to map few menu variants as in mui, for that i cannot hardcode divider, if there is any way i can manage it with Map or any other method. Thanks.
export const Menu= ({ icons }) => {
return (
<Paper sx={{ width: 320, maxWidth: '100%' }} >
<MenuList>
{icons.map((item) => (
<MenuItem>
<ListItemIcon fontSize="small">{item.icon}</ListItemIcon>
<ListItemText>{item.label}</ListItemText>
<Typography variant="body2" color="text.secondary">{item.typography}</Typography>
</MenuItem>
))}
<Divider /> /* how do i map this */
</MenuList>
</Paper >
);
}
Stories.js
icons: [
{ icon: <ContentCut fontSize="small" />, typography: "⌘X", label: "Cut" },
{ icon: <ContentCopy fontSize="small" />, typography: "⌘C", label: "Copy" },
]
Answer:
If you want the divider to be just one then don't map over it . thats the purpose of the .map() method.
and To Acheive the required results i just removed <Menu></Menu> Component and Just Kept the <Papper></Papper> Component
Notes :
In terms of how to Map the Divider with the below example ,you can just wrap it in a empty react fragment<></> and map over the <MenuItem></MenuItem> .
Only issue is that youll get an error in your key props which will say its not unique it can be fixed by assigning index key like the example below and wrap the <MenuItem></MenuItem> Component in It. However thats not best practice ,
<React.Fragment></React.Fragment> Is better practice according to Keyed Fragment React 18 Docs to add a key prop However that's giving a New Error in MUI.
Thats not an issue since were mapping over the MenuItem Component , However if we use for example in #Nathan Comments <React.Fragment key={index}></React.Fragment> or my previous answer to use <></> we would be mapping over the React.Fragment Itself or the empty fragment and would get a new error MUI: The Menu component doesn't accept a Fragment as a child. Uncomment the Examples in the Sandbox Check the sandbox console.
Check Code Code SandBox
Solution
export const MenuIcon = ({ menuicons }) => {
return (
<Paper sx={{ width: 320, maxWidth: "100%" }}>
{menuicons.map((item, index) => (
<MenuItem key={item + index}>
<ListItemIcon fontSize="small">{item.icon}</ListItemIcon>
<ListItemText>{item.label}</ListItemText>
<Typography variant="body2" color="text.secondary">
{item.typography}
</Typography>
</MenuItem>
))}
<Divider />
<ListItemIcon fontSize="small">
ClipBoard <ContentCopyIcon fontSize="small" />
</ListItemIcon>
</Paper>
);
}
References
Empty Fragment Syntax React Docs
Stack OverFlow Question MUI Icons - as props
.map() method Syntax - MDN Docs

Showing a VisX graph inside a Semantic-UI-React Modal causes problems with z-index

I'm adding a VisX graph inside Semantic-UI-React Modal.
The graph by itself shows the tooltip, crosshair and series glyphs correctly:
But when it's in a modal, all those appear beneath the modal:
I can reconstruct the tooltip with a higher z-index in the component I supply for the renderTooltip property, but it's lacking the crosshair and series glyph:
As these elements are added to the DOM on hover, it's impossible for me to catch them int he devtools and see what styles they have and inherit.
Is there some way I can set their z-index or fix this in some other way?
const Visx: FC = () => {
return (
<Modal open>
<Modal.Content>
<XYChart width={900} height={500} xScale={{ type: 'time' }} yScale={{ type: 'linear' }}>
<Grid rows numTicks={maxCount + 1} />
<Axis
orientation="left"
label="Play count"
numTicks={maxCount + 1}
tickFormat={(value) => {
return value;
}}
/>
<Axis orientation="bottom" label="Date" />
<LineSeries dataKey="plays" data={data} {...accessors} />
<Tooltip
showHorizontalCrosshair
showVerticalCrosshair
snapTooltipToDatumX
snapTooltipToDatumY
showSeriesGlyphs
showDatumGlyph
renderTooltip={({ tooltipData }) => {
const datum = tooltipData.nearestDatum?.datum as DataPoint | null;
return (
<div>
{datum?.count || 'no'} plays on {moment(datum?.date).format('MMM D, YYYY')}
</div>
);
}}
/>
</XYChart>
</Modal.Content>
</Modal>
);
};
Fixed it by adding this global CSS style:
.visx-tooltip {
z-index: 9999; /* or whatever height is appropriate */
}

How to make the Collapse position to bottom-right after clicking on expand icon in AntD

I am using AntD Collapse for displaying a list of items after expand icon is clicked.
I want the position of expandIcon to go to bottom-right after all the list of the data when expand icon is clicked (just like in google news), but found only two options (left|right) for 'expandIconPosition', no option for top or bottom.
How can we align the expandIcon to bottom-right, when expand icon is clicked?
Few lines from the code for reference:
<Collapse
ghost
style={{ marginTop: "-1vh" }}
expandIcon={({ isActive }) => (
<DownOutlined
style={{ marginTop: "-2vh" }}
rotate={isActive ? 180 : 0}
/>
)}
expandIconPosition="right"
>
<Panel>
<div>
{list()} //list of items
</div>
</Panel>
</Collapse>
Here's one possible solution. Make Collapse a controlled component by specifying activeKey prop and then the value of it will be based on state. Then, by tracking the activeKeys state you can now do a conditional rendering (hide and show) on icons:
const [activePanelKeys, setActivePanelKeys] = useState([]);
const handlePanelIconClick = (panelKey, makeActive) => {
if (makeActive) {
setActivePanelKeys([...activePanelKeys, panelKey]);
} else {
setActivePanelKeys(activePanelKeys.filter((aPK) => aPK !== panelKey));
}
};
<Collapse
activeKey={activePanelKeys}
expandIconPosition="right"
expandIcon={() => <DownOutlined />}
// expandIcon={(panelProps) => (
// <DownOutlined
// onClick={() => handlePanelIconClick(panelProps.panelKey, true)}
// />
// )}
onChange={e => setActivePanelKeys(e)} //if you want to click only icon, comment this and uncomment the above expandedIcon
>
<Panel
header="This is panel header 1"
key="p1"
showArrow={activePanelKeys.indexOf("p1") === -1}
>
<div>{text}</div>
{activePanelKeys.indexOf("p1") !== -1 && (
<div style={{ textAlign: "right", marginTop: 10 }}>
<UpOutlined onClick={() => handlePanelIconClick("p1", false)} />
</div>
)}
</Panel>
{/* <PanelContent header="This is panel header 2" key="p2">
{text}
</PanelContent> */}
</Collapse>;
Here is the complete sample code:
Note: I tried to make a reusable Panel component but it seems that the reveal animation were gone. You can uncomment the commented PanelContent on the code to see the difference.
Hope that I hit what you want.

React Semantic UI - How to disable a child component based on parent

How does one disable the input box here, depending on whether a checkbox has been checked or not?
I have verified the checked property - it is in working order (shows true or false boolean values).
However, I can't seem to get the disabled property in Input to work.
Below is my code:
import React from 'react';
import { Button, Checkbox, Input, List } from 'semantic-ui-react'
import PropTypes from 'prop-types';
const CategoryCheckBox = ({ type = 'checkbox', name, mylabel, checked, onChange }) => (
<React.Fragment>
<List horizontal relaxed>
<List.Item>
<Checkbox style={{ paddingLeft:"1em", paddingBottom: "1em" }} label={mylabel} checked={checked} onChange={onChange} />
<List.Content>
<Input style={{ maxWidth:"9em", paddingLeft:"1em" }} size='mini' focus placeholder='Min' disabled={checked === true ? true : false} />
<Input style={{ maxWidth:"9em", paddingLeft:"1em" }} size='mini' focus placeholder='Max' />
</List.Content>
</List.Item>
</List>
</React.Fragment>
);
CategoryCheckBox.propTypes = {
type: PropTypes.string,
name: PropTypes.string.isRequired,
mylabel: PropTypes.string.isRequired,
checked: PropTypes.bool,
onChange: PropTypes.func.isRequired,
}
export default CategoryCheckBox;
From the main program,
The component is called with the below parameters:
<CategoryCheckBox name={item.value} mylabel={item.text} checked={this.state.checkedItems.get(item.value)} onChange={this.handleChange} />
Below is my screenshot for the component along with React debugger showing the checked value.
Any Help will be highly appreciated.
Tried to set up most of the important code - Newbie to React myself. Can't get the index.js in the working order. But it gives you a good idea of my code https://codesandbox.io/embed/2pyoxpr6rn?fontsize=14
Changes:
1- You are not assigning the name to CheckBox element in CategoryCheckBox, add name here:
<Checkbox
style={{ paddingLeft: "1em", paddingBottom: "1em" }}
label={mylabel}
// ↓↓↓↓↓↓↓↓ here
name={name}
checked={checked}
onChange={onChange}
/>
2- Add disable condition for Max input field also:
<Input
style={{ maxWidth: "9em", paddingLeft: "1em" }}
size="mini"
focus
placeholder="Max"
// ↓↓↓↓↓↓↓↓ here
disabled={!checked}
/>
3- Most importantly, You are storing data in states in App component so it needs to be a class component.
Check Working Codesandbox with all these changes.
After looking at your code the problem is with your app component. Your app component has a state and therefore cannot be a stateless functional component. Your App component should look something like this.
import React from "react";
import ReactDOM from "react-dom";
import { Checkbox, Label, Header, Card, Form, Button, Container, Icon, Step, Select, Dropdown, List } from 'semantic-ui-react';
import womensBoutiqueOptions from "./womensBoutiqueOptions";
import CategoryCheckBox from "./CategoryCheckBox";
import "./styles.css";
class App() extends React.Component {
state = {
date: new Date(),
time: '10:00',
checkedItems: new Map()
}
handleChange(e) {
const item = e.target.name;
const isChecked = e.target.checked;
this.setState(prevState => ({ checkedItems: prevState.checkedItems.set(item, isChecked) }));
}
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Form size="large" key="large">
<h4 className="ui dividing header">Womens Information</h4>
<Form.Group widths='equal'>
<Form.Field>
<React.Fragment>
<List horizontal >
{
womensBoutiqueOptions.map(item => (
<List.Item key={item.key}>
<List.Content>
<CategoryCheckBox name={item.value} mylabel={item.text} checked={this.state.checkedItems.get(item.value)} onChange={this.handleChange} />
</List.Content>
</List.Item>
))
}
</List>
</React.Fragment>
</Form.Field>
</Form.Group>
</Form>
</div>
)
}
);
}
Check out the react documentation for some more information on why

How can I have full-height Tabs inside of a Toolbar using material-ui?

I am trying to have a fixed header where on the right side should be tabs. The <Toolbar /> component is responsible for the responsiveness of the block but doesn't allow for stretched tabs so easily.
https://codesandbox.io/s/jv8v6vwqpv
The problem is that the Toolbar responsively changes its height and the Tabs and Tab component do not (Tabs sets a min-height of 48px in its root class, Tab sets a height in its root class).
Fortunately, the behavior Toolbar uses is available in a theme mixin, so you can create classes that also use this logic:
const styles = theme => ({
fullHeight: {
...theme.mixins.toolbar,
},
});
This will create a class that has the same responsive height logic used in the Toolbar component. Using withStyles, you can make this class accessible to your component:
import { withStyles } from "material-ui/styles";
// ...
export default withStyles(styles)(Header);
This will add a classes prop, which is an object containing a string attribute for each class defined in the object provided to withStyles. You can apply this to the Tabs component and each Tab component by overriding their root classes to ensure that they fill the AppBar:
render() {
const { classes } = this.props;
return (
<AppBar>
<Toolbar>
<Grid container alignItems="center" justify="space-between">
<Grid item>
<Typography color="inherit" variant="title">
BackTube
</Typography>
</Grid>
<Grid item>
<Tabs classes={{ root: classes.fullHeight }} onChange={this.changeTab} value={this.state.currentTab}>
<Tab classes={{ root: classes.fullHeight }} icon={<Magnify />} value="search" />
<Tab classes={{ root: classes.fullHeight }} icon={<FormatListBulleted />} value="lists" />
<Tab classes={{ root: classes.fullHeight }} icon={<Settings />} value="settings" />
</Tabs>
</Grid>
</Grid>
</Toolbar>
</AppBar>
);
Please note that the above solution was written for MUI v1 beta.
UPDATED 5/2022: The same thing can be accomplished in MUI 5, here is a codesandbox

Resources