I am using a headless UI tab component and when I add padding to the buttons as in below code, I expect all the buttons to have uniform padding but there seems to be some issues here.
Headless UI tabs component:
<Tab.List className="flex sm:flex-col">
<Tab>
{({ selected }) => (
<button
className={`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`}
>
Frontend
</button>
)}
</Tab>
<Tab>
{({ selected }) => (
<button
className={`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`}
>
Backend
</button>
)}
</Tab>
<Tab>
{({ selected }) => (
<button
className={`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`}
>
Multimedia
</button>
)}
</Tab>
</Tab.List>
Result:
Possible Cause:
Button padding seems to be rendering twice by headless UI otherwise button itself has the required padding.
Also if it is of any help, I have added the .babelrc.js and updated the _document.js for making twin macro work:
.babelrc.js
module.exports = {
presets: [['next/babel', { 'preset-react': { runtime: 'automatic' } }]],
plugins: ['babel-plugin-macros', ['styled-components', { ssr: true }]],
}
_document.js
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
Any help or suggestion is greatly appreciated
EDIT:
Changing the button to a div solved the issue. I am still not quite sure how it solved though
Tab itself renders a button. So, to prevent nesting a button element inside another, you need to use the as prop on the Tab component:
<Tab.List className="flex sm:flex-col">
<Tab as={Fragment}>
{({ selected }) => (
<button
className={`px-6 py-4 ${
selected ? 'bg-white text-black' : 'bg-red-600 text-white'
}`}
>
Frontend
</button>
)}
</Tab>
{/*...*/}
</Tab.List>
You can also do:
<Tab.List className="flex sm:flex-col">
<Tab
className={({ selected }) =>
`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`
}
>
Frontend
</Tab>
{/*...*/}
</Tab.List>
Reference: https://headlessui.dev/react/tabs#styling-the-selected-tab
Related
I made the following using the nextjs and framer motion
I have a list of images that I'm mapping over and assigning them a layoutid and an optional variant to animate. The layoutid corresponds to the layoutid on the model1, model2, model3 pages.
Current Behaviour
When first going to the home page and clicking on an image I update some state and set the variant animation to false, this then tells that image to use the layoutid, it then fades out the other images and animates the clicked image into place on the component that is loaded (model1, model2, model3)...Great it works!
If you then click home in the navigation and try clicking an item again it doesn't work, all images are faded out and the clicked image doesn't animated.
Click refresh on the homepage and it works as desired!
here is the code for the page, I suspect it could be something to do with the routing or settings in _app.js
export default function Home() {
const router = useRouter();
const [isClicked, setIsClicked] = useState(null);
const onHandlerClick = (item, href, e) => {
e.preventDefault();
setIsClicked(item);
router.push(href, { scroll: false });
};
return (
<div className="l-grid l-grid-outter">
<div className="c-home-maincontent">
<div>
<main>
<motion.div className="l-grid-3-col" initial="initial" animate="enter" exit="exit" variants={{ exit: { transition: { staggerChildren: 0.1 } } }}>
{images.map((item, index) => {
return (
<motion.div
key={index}
className="c-home-overflowimage c-home-overflowimage2"
layoutId={`imageAnimation${item}`}
variants={isClicked === item ? false : postVariants}
transition={{ ...transition }}
>
<a href={`/model${item}`} onClick={(event) => onHandlerClick(item, `/model${item}`, event)}>
<motion.img
src="/yasmeen.webp"
whileHover={{
scale: 1.1,
}}
/>
</a>
</motion.div>
);
})}
</motion.div>
</main>
</div>
</div>
<Footer />
</div>
);
}
function MyApp({ Component, pageProps }) {
const router = useRouter();
return (
<>
<DefaultSeo {...Seo} />
<AnimateSharedLayout type="crossfade">
<AnimatePresence exitBeforeEnter initial={false}>
<Component {...pageProps} key={router.asPath} />
</AnimatePresence>
</AnimateSharedLayout>
</>
);
}
export default MyApp;
Updated the code to include an animate set to false if its the clicked item
<motion.div className="l-grid-3-col" initial="initial" animate="enter" exit="exit">
{images.map((item, index) => {
return (
<motion.div
key={index}
className="c-home-overflowimage c-home-overflowimage2"
layoutId={`imageAnimation${item}`}
animate={isClicked === item ? false : true}
variants={isClicked === item ? false : postVariants}
transition={{ ...transition }}
>
<a href={`/model${item}`} onClick={(event) => onHandlerClick(item, `/model${item}`, event)}>
<motion.img
src="/yasmeen.webp"
whileHover={{
scale: 1.1,
}}
/>
</a>
</motion.div>
);
})}
</motion.div>
I have Drawer class component and I want to make marginTop for that Drawer, but I can't this is my code
const theme = createMuiTheme({
root: {
marginTop: '40px'
},
})
class PageMenu extends React.Component {
render () {
return (
<div>
<Drawer
classes={{paper: classes.drawerPaper }}
>
<List>
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider />
</Drawer>
</div>
)}
i want to make it working in class component
You can just add another class name to it and then style it in your CSS file by the following lines of code:
.classname{
margin-top:yourNumber;
}
I have designed a form with validation using TypeScript Material UI and Formik. I want a material UI Icon to appear in my textfield area, here's my code:
import React from 'react'
import { Formik, Form, FieldAttributes,useField} from 'formik'
import { TextField } from '#material-ui/core'
import CalendarTodayIcon from '#material-ui/icons/CalendarToday'
import * as yup from 'yup'
import './MainInfo.css'
const MyTextField: React.FC<FieldAttributes<{}>> = ({
placeholder,type,className,style,
...props
}) => {
const [field, meta] = useField<{}>(props);
const errorText = meta.error && meta.touched ? meta.error : "";
return (
<div className='container'>
<TextField
placeholder={placeholder}
className={className}
style={style}
type={type}
{...field}
helperText={errorText}
error={!!errorText}
id="outlined-basic"
variant="outlined"
/>
</div>
);
};
export function MainInfo() {
return (
<div>
<Formik
validateOnChange={true} validationSchema={validationSchema} initialValues={{ Title: '', ActivationDate: '', ExpirationDate: '', DirectManager: '', HRBP: '' }} onSubmit={(data) => {
console.log(data)
}}
>
{({values, errors}) => (
<Form id='my-form' >
<div>
<label className='label'>عنوان</label>
<div >
<MyTextField style={{width:'60%'}} placeholder='طراح' name='Title' type='input' />
</div>
...
</div>
</Form>
)}
</Formik>
</div>
)
}
but the problem is that I can not add a new Icon property or InputProp since <FieldAttributes<{}>> doesnt accept it. how can I define a new property for the FieldAttributes or fix this issue?
Use the TextField Props InputProps to customize the input field
And use startAdornment, endAdornment to customize the prefix/suffix
Finally use icon inside InputAdornment would be fine
import { TextField, InputAdornment } from "#material-ui/core";
import ExpandLess from "#material-ui/icons/ExpandLess";
import ExpandMore from "#material-ui/icons/ExpandMore";
<TextField
id="standard-basic"
label="Standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<ExpandLess />
</InputAdornment>
),
endAdornment: (
<InputAdornment position="end">
<ExpandMore />
</InputAdornment>
)
}}
/>
Refer:
MUI TextField Props API: InputProps, startAdornment, endAdornment
MUI InputInputAdornment Props API
online demo: https://stackblitz.com/edit/gzlbzm
I'm using a material UI library in a React project using react typescript. I want this button to have a picture as a background. However, the button does not accept src or imageURL and returns a typescript error and the css style background doesn't show the picture either. this is my code:
const noticon = require ('./../../images/nicon.png')
const Avatarpic = require ('./../../images/Avatar.png')
const ExampleButton = ({
// useOpenState hook handlers
handleToggle, handleClose, handleOpen, setOpenState, isOpen
}: DropdownButtonProps) => (
<Button onClick={handleToggle} style={{backgroundImage: '{noticon}'}} square>
</Button>
)
function Navbar () {
return (
<>
<TopBar style={{ backgroundColor: '#e6edec' }}>
<TopBarSection>
<TopBarTitle>
<Avatar imgUrl={Avatarpic} name='حسین ساداتی پور' style={{ fontFamily: 'IranSans', fontSize: '20px' }} />
</TopBarTitle>
<Dropdown ButtonComponent={ExampleButton}>
<DropdownItem>Item to click</DropdownItem>
</Dropdown>
</TopBarSection>
{// <TopBarSection>
// burger menu Icon
// </TopBarSection>
}
</TopBar>
<section
style={{
padding: 50,
textAlign: 'center'
}}
>
Some content
</section>
</>
)
}
export default Navbar
you need to do this instead:
<Button onClick={handleToggle} style={{backgroundImage: `url(${noticon})`}} square>
I've made a custom User Confirmation Dialog from Material UI Dialog component like here
I faced a problem to overwrite the Dialog's font. I can overwrite color or background color, but fonts in Dialog's header or buttons are inherited from Material-UI. I successfully overwrote Material-UI fonts in other components, but not in this part with callback:
const UserConfirmation = (
message: string,
callback: (shouldNavigate: boolean) => void
) => {
const container = document.createElement('div')
container.setAttribute('custom-confirmation-navigation', '')
document.body.appendChild(container)
const closeModal = (shouldNavigate: boolean) => {
ReactDOM.unmountComponentAtNode(container)
callback(shouldNavigate)
}
ReactDOM.render(
<>
<Dialog
fullWidth={true}
maxWidth="sm"
open={true}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitleWrapper
style={{fontFamily: `BuenosAires !important`, color: `orange`}}
>
Discard draft?
</DialogTitleWrapper>
<DialogContent>
<p> {message} </p>
</DialogContent>
<DialogActionsWrapper>
<Button
onClick={() => closeModal(true)}
fullWidth={true}
variant="outlined"
label="Discard"
/>
<div style={{ width: '80%' }} />
<Button
onClick={() => closeModal(false)}
fullWidth={true}
variant="contained"
label="Cancel"
/>
</DialogActionsWrapper>
</Dialog>
</>,
container
)
}
export default UserConfirmation
Thank Alex
That works brilliant for me:
<DialogTitle disableTypography="true">
Also, buttons' labels were fixed by that:
label={<h5 style={{ textTransform: 'none' }}>Cancel</h5>}
You can use classes object to Override or extend the styles applied to the component.
here
create custom styles like below
const useStyles = makeStyles({
customDialogTitle: {
fontFamily:'Impact'//sans-serif
}
});
and assign to classes
<DialogTitle disableTypography="true"
classes={{
root: classes.customDialogTitle
}}
>
.....
</DialogTitle>
sample sandbox