Material-UI <Radio /> with a <Button />-like appearance - reactjs

Using only Material-UI, is there any way to style <Radio /> objects with a <Button /> type of appearance? If not, what would be the most simple alternative?
After spending the past few days reading documentation and experimenting, I don't feel any closer to a solution. Thanks to anyone who can lend some guidance.
Here's my starting point (without the <Button /> experiments) in case anyone would like to use what I'm working with:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import RadioGroup from '#material-ui/core/RadioGroup';
import Radio from '#material-ui/core/Radio';
import Button from '#material-ui/core/Button';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
const styles = theme => ({
textField: {
marginLeft: theme.spacing.unit,
marginRight: theme.spacing.unit,
width: '100%',
},
formControl: {
display: 'flex',
flexBasis: '100%',
alignItems: 'center',
}
});
class QRadios extends React.PureComponent {
constructor(props, context) {
super(props, context);
this.state = {
value: this.props.value,
};
}
handleChange = event => {
this.setState({
value: event.target.value,
},
this.props.onChange(event));
};
render() {
const { classes } = this.props;
return (
<FormControl component="ul" className={classes.formControl} required>
<RadioGroup
row={true}
id={this.props.id}
name={this.props.name}
value={this.state.value}
onChange={this.handleChange}
>
<FormControlLabel
htmlFor={this.props.id}
value="good"
control={<Radio />}
/>
<FormControlLabel
htmlFor={this.props.id}
value="okay"
control={<Radio />}
/>
<FormControlLabel
htmlFor={this.props.id}
value="bad"
control={<Radio />}
/>
<FormControlLabel
htmlFor={this.props.id}
value="na"
control={<Radio />}
/>
</RadioGroup>
</FormControl>
);
}
}
QRadios.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(QRadios);
Update:
For anyone who is using an older version of Material-UI that lacks the built-in solution as per the answer below, you'll have to create your own CSS for the buttons. If you need help, this is how I implemented it:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import green from '#material-ui/core/colors/green';
import yellow from '#material-ui/core/colors/yellow';
import red from '#material-ui/core/colors/red';
import grey from '#material-ui/core/colors/grey';
import RadioGroup from '#material-ui/core/RadioGroup';
import Radio from '#material-ui/core/Radio';
import FormControl from '#material-ui/core/FormControl';
import InputLabel from '#material-ui/core/InputLabel';
const styles = theme => ({
formControl: {
display: 'flex',
flexBasis: '100%',
alignItems: 'stretch',
margin: theme.spacing.unit * 3 / 2
},
formGroup: {
alignItems: 'stretch',
justifyContent: 'space-around',
flexWrap: 'nowrap'
},
radioFlex: {
flex: '1 1 auto',
margin: '0 5px'
},
greenButtonRoot: {
backgroundColor: '#00000004',
borderRadius: 5,
border: '1px solid',
color: green.A700,
fontFamily: 'monospace',
fontSize: '180%',
height: 32,
'&$checked': {
backgroundColor: green.A700,
color: 'white'
},
'&:not($checked):hover': {
backgroundColor: green['50']
},
transition: 'background-color 250ms'
},
yellowButtonRoot: {
backgroundColor: '#00000004',
borderRadius: 5,
border: '1px solid',
color: yellow['700'],
fontFamily: 'monospace',
fontSize: '200%',
height: 32,
'&$checked': {
backgroundColor: yellow.A700,
color: 'white'
},
'&:not($checked):hover': {
backgroundColor: yellow['100']
},
transition: 'background-color 250ms'
},
redButtonRoot: {
backgroundColor: '#00000004',
borderRadius: 5,
border: '1px solid',
color: red.A700,
fontFamily: 'monospace',
fontSize: '160%',
height: 32,
'&$checked': {
backgroundColor: red.A700,
color: 'white'
},
'&:not($checked):hover': {
backgroundColor: red['50']
},
transition: 'background-color 250ms'
},
greyButtonRoot: {
backgroundColor: '#00000004',
borderRadius: 5,
border: '1px solid',
color: grey['700'],
fontFamily: 'monospace',
fontSize: '180%',
height: 32,
'&$checked': {
backgroundColor: grey['700'],
color: 'white'
},
'&:not($checked):hover': {
backgroundColor: grey['200']
},
transition: 'background-color 250ms'
},
disabled: {
backgroundColor: '#00000004'
},
checked: {}
});
function QRadios(props) {
const {
classes,
error,
required,
id,
label,
name,
binaryChoice,
value,
onChange,
onBlur
} = props;
return (
<FormControl className={classes.formControl} required={required}>
<InputLabel
error={error}
required={required}
shrink
style={{
position: 'relative',
marginBottom: '10px'
}}
>
{label}
</InputLabel>
<RadioGroup
className={classes.formGroup}
row
id={id}
name={name}
value={value}
onChange={onChange}
onBlur={onBlur}
>
<Radio
htmlFor={id}
className={classes.radioFlex}
value="good"
classes={{
root: classes.greenButtonRoot,
checked: classes.checked
}}
icon="〇"
checkedIcon="〇"
/>
<Radio
htmlFor={id}
className={classes.radioFlex}
value="okay"
classes={{
root: classes.yellowButtonRoot,
checked: classes.checked,
disabled: classes.disabled
}}
icon="△"
checkedIcon="△"
disabled={binaryChoice}
/>
<Radio
htmlFor={id}
className={classes.radioFlex}
value="bad"
classes={{
root: classes.redButtonRoot,
checked: classes.checked
}}
icon="✕"
checkedIcon="✕"
/>
<Radio
htmlFor={id}
className={classes.radioFlex}
value="na"
classes={{
root: classes.greyButtonRoot,
checked: classes.checked
}}
icon="-"
checkedIcon="-"
/>
</RadioGroup>
</FormControl>
);
}
QRadios.propTypes = {
classes: PropTypes.object.isRequired,
required: PropTypes.bool,
error: PropTypes.bool,
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
binaryChoice: PropTypes.bool,
value: PropTypes.string,
onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func
};
QRadios.defaultProps = {
required: false,
binaryChoice: false,
error: false,
onBlur: null,
value: ''
};
export default withStyles(styles)(QRadios);
Usage...
<QRadios
error={!whateverThing.isValid}
id="whateverThing"
name="whateverThing"
label="What's your judgement of whateverThing?"
value={whateverThing.value}
onChange={this.someHandlerFunc}
onBlur={this.someCheckFunc}
/>

Have you looked into https://material-ui.com/components/toggle-button/ or https://material-ui.com/api/toggle-button-group/? I think it's a relatively new addition (i.e. didn't exist when you resolved this), but it might be helpful for anyone who finds this question later.
The ToggleButtonGroup will control the selected state of its child buttons when given its own value prop.
Here's the example given on that page:
<ToggleButtonGroup
value={alignment}
exclusive
onChange={handleAlignment}
aria-label="text alignment"
>
<ToggleButton value="left" aria-label="left aligned">
<FormatAlignLeftIcon />
</ToggleButton>
<ToggleButton value="center" aria-label="centered">
<FormatAlignCenterIcon />
</ToggleButton>
<ToggleButton value="right" aria-label="right aligned">
<FormatAlignRightIcon />
</ToggleButton>
<ToggleButton value="justify" aria-label="justified" disabled>
<FormatAlignJustifyIcon />
</ToggleButton>
</ToggleButtonGroup>

This was you can make a radio button have a button like, i have created a pen for this please check https://codepen.io/praveen-rao-chavan/pen/JBpgLX
<section>
<h1>Simple material design CSS only radio button example</h1>
<div>
<ul class="donate-now">
<li class="md-radio">
<input id="1" type="radio" name="g" checked>
<label for="1">Option 1</label>
</li>
<li class="md-radio">
<input id="2" type="radio" name="g">
<label for="2">Option 2</label>
</li>
</ul>
</div>
</section>
CSS
#import url(https://fonts.googleapis.com/css?family=Roboto);
$md-radio-checked-color: rgb(51, 122, 183);
$md-radio-border-color: rgba(0, 0, 0, 0.54);
$md-radio-size: 20px;
$md-radio-checked-size: 10px;
$md-radio-ripple-size: 15px;
#keyframes ripple {
0% {
box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.0);
}
50% {
box-shadow: 0px 0px 0px $md-radio-ripple-size rgba(0, 0, 0, 0.1);
}
100% {
box-shadow: 0px 0px 0px $md-radio-ripple-size rgba(0, 0, 0, 0);
}
}
.md-radio {
margin: 16px 0;
&.md-radio-inline {
display: inline-block;
}
input[type="radio"] {
display: none;
&:checked + label:before {
--border-color: $md-radio-checked-color;
--animation: ripple 0.2s linear forwards;
}
&:checked + label:after {
--transform: scale(1);
}
}
label {
display: inline-block;
height:$md-radio-size;
position: relative;
padding: 0 ($md-radio-size + 10px);
margin-bottom: 0;
cursor: pointer;
vertical-align: bottom;
&:before, &:after {
position: absolute;
content: '';
border-radius: 50%;
transition: all .3s ease;
transition-property: transform, border-color;
}
&:before {
left: 0;
top: 0;
width: $md-radio-size;
height: $md-radio-size;
border: 2px solid $md-radio-border-color;
}
&:after {
top: $md-radio-size / 2 - $md-radio-checked-size / 2;
left: $md-radio-size / 2 - $md-radio-checked-size / 2;
width:$md-radio-checked-size;
height:$md-radio-checked-size;
transform: scale(0);
background:$md-radio-checked-color;
}
}
}
// *************************************
// *************************************
*, *:before, *:after {
box-sizing: border-box;
}
body {
background:#f0f0f0;
position: absolute;
width:100%;
padding:0;
margin:0;
font-family: "Roboto", sans-serif;
color: #333;
}
section {
background:white;
margin:0 auto;
padding: 4em;
max-width: 800px;
h1 {
margin: 0 0 2em;
}
}
.donate-now {
list-style-type:none;
margin:25px 0 0 0;
padding:0;
}
.donate-now li {
float:left;
margin:0 5px 0 0;
width:100px;
height:40px;
position:relative;
}
.donate-now label, .donate-now input {
display:block;
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
}
.donate-now input[type="radio"] {
opacity:0.011;
z-index:100;
}
.donate-now input[type="radio"]:checked + label {
background:yellow;
}
.donate-now label {
padding:5px;
border:1px solid #CCC;
cursor:pointer;
z-index:90;
}
.donate-now label:hover {
background:#DDD;
}
You can customize it to your styles.

I use MUi5 toggle button and overwrite their style to become button-like
check my codesandbox link

Related

How to add a label to a border in mui?

I would like to have a list wrapped in a border which looks and behaves the same as a textfield border:
Example textfield and list which should have both same border.
In the image, the border around the list looks similar than the one around the textfield but most notably, the label is missing. How can I add the label and how would I set up the focus listeners to get the same hover and selection behaviour?
The typescript code for the list:
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600'}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I am also open for alternative approaches. Thanks for the help.
Here is my answer using React and Mui (only for icon).
It relies on flex.
We have a main container that only draws its left, bottom and right borders.
Then we have a header container in charge of drawing the top border in two parts (before and after) and a section with an icon and title.
You can either pass an icon and a title, just a title, just an icon, or nothing at all.
borderedSection.js:
import React from "react";
import SvgIcon from "#mui/material/SvgIcon";
import styles from "./borderedSection.module.scss";
function BorderedSection({ icon, title, children }) {
return (
<div className={styles.mainContainer}>
<div className={styles.header}>
<div className={styles.headerBorderBefore}></div>
{(icon || title) && (
<div className={styles.headerTitle}>
{icon && <SvgIcon component={icon} />}
{title && <span className={styles.title}>{title}</span>}
</div>
)}
<div className={styles.headerBorderAfter}></div>
</div>
<div className={styles.childrenContainer}>{children}</div>
</div>
);
}
export default BorderedSection;
borderedSection.module.scss:
$border-color: #b2b2b2;
.mainContainer {
display: flex;
flex-direction: column;
max-width: 100%;
border-left: 1px solid $border-color;
border-bottom: 1px solid $border-color;
border-right: 1px solid $border-color;
border-radius: 5px;
margin: 1em;
.childrenContainer {
padding: 1em;
}
.header {
display: flex;
flex-direction: row;
width: 100% !important;
.headerBorderBefore {
border-top: 1px solid $border-color;
width: 1em;
border-top-left-radius: 5px;
}
.headerTitle {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
gap: 0.25em;
width: fit-content;
height: 2em;
margin: -1em 0.5em 0em 0.5em;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1em;
font-weight: 600;
}
.headerBorderAfter {
border-top: 1px solid $border-color;
width: 1em;
flex-grow: 2;
border-top-right-radius: 5px;
}
}
}
usage:
import React from "react";
import BorderedSection from "./borderedSection";
import InfoIcon from "#mui/icons-material/Info";
function Example() {
return (
<div style={{ padding: "2em" }}>
<BorderedSection icon={InfoIcon} title="Icon and title">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection title="Title only">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection icon={InfoIcon} >
<div>Icon only</div>
<div>a second child with quite a long text</div>
</BorderedSection>
<BorderedSection >
<div>No icon and no title</div>
<div>a second child with quite a long text</div>
</BorderedSection>
</div>
);
}
Here is how it looks:
I hope it helps
I now managed to hack a solution which looks the same. I do still hope though that there is a clean way to do this: result.
<FormLabel style={{marginLeft: "0.71em", marginTop: "-0.71em", paddingLeft: "0.44em", zIndex: 2, width: "4.2em", backgroundColor: "#383838", position: "absolute", fontSize: "0.75em"}}>Damage</FormLabel>
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600', "&:hover": { borderColor: 'grey.200' }}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I needed the same thing. As I was poking around I noticed that MUI accomplished this by using the fieldset tag. I created a quick and dirty component (OutlinedBox) to get this effect:
import React from "react";
import {Box, FormLabel} from "#mui/material";
const OutlinedBox = (props) => {
const {
label,
children
} = props;
return (
<Box>
<FormLabel
sx={{
marginLeft: "0.71em",
marginTop: "-0.71em",
paddingLeft: "0.44em",
paddingRight: '0.44em',
zIndex: 2,
backgroundColor: (theme) => theme.palette.background.default,
position: "absolute",
fontSize: "0.75em",
width: 'auto',
}}>{label}</FormLabel>
<Box
sx={{
position: 'relative',
borderRadius: theme => theme.shape.borderRadius + 'px',
fontSize: '0.875rem',
}}
>
<Box
sx={{
padding: (theme) => theme.spacing(1),
display: 'flex',
gap: (theme) => theme.spacing(1),
flexWrap: 'wrap',
overflow: 'auto'
}}
>
{children}
</Box>
<fieldset aria-hidden={"true"} style={{
textAlign: 'left',
position: 'absolute',
bottom: 0,
right: 0,
top: '-5px',
left: 0,
margin: 0,
padding: '0 8px',
pointerEvents: 'none',
borderRadius: 'inherit',
borderStyle: 'solid',
borderWidth: '1px',
overflow: 'hidden',
minWidth: '0%',
borderColor: 'rgba(255, 255, 255, 0.23)',
}}
>
<legend style={{
float: 'unset',
overflow: 'hidden',
display: 'block',
width: 'auto',
padding: 0,
height: '11px',
fontSize: '0.75em',
visibility: 'hidden',
maxWidth: '100%',
'-webkit-transition': 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
transition: 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
whiteSpace: 'nowrap',
}}><span>{label}</span></legend>
</fieldset>
</Box>
</Box>
);
}
export { OutlinedBox };
// Example usage: <OutlinedBox label="Test">Some content here</OutlinedBox>
I figured I'd post it here in case anyone needs the same thing and comes across this question. All the styling stuff was copied from the styles MUI was using. There may be a better way to read some of this off of the theme, so if anyone decides to use this you may want to tweak it some.

How can I add Adornment inside MUI InputBase?

I am trying to place MUI Adornment inside of MUI InputBase, but so far I can only get it to render outside of the input:
<InputField
id={id}
ref={ref}
error={error}
type={type}
multiline={multiline}
minRows={minRows}
inputProps={inputProps}
endAdornment={
<InputAdornment position="end">adornment</InputAdornment>
}
{...props}
/>
https://codesandbox.io/s/ecstatic-pond-yvi19?file=/src/CustomTextField.js:1320-1956
Just move below styles to InputContainer instead of InputField:
box-shadow: 0 1px 2px 0 rgba(184, 200, 224, 0.22);
border: 1px solid
${(props) => (props.error ? props.theme.palette.error.dark : "#d8e0f0")};
border-radius: 14px;
So, based on mentioned description, you have:
export const InputField = styled(InputBase)`
& > .MuiInputBase-input {
font-family: Raleway;
padding: 10px 16px;
}
`;
export const InputContainer = styled("div")`
display: flex;
flex-direction: column;
box-shadow: 0 1px 2px 0 rgba(184, 200, 224, 0.22);
border: 1px solid
${(props) => (props.error ? props.theme.palette.error.dark : "#d8e0f0")};
border-radius: 14px;
`;
`const useStyles = makeStyles((theme) => ({
inputfield: {
"& .MuiInputBase-root": {
borderRadius: 4,
backgroundColor: "#FCFCFC",
border: "1px solid #D4DEF5",
fontSize: 16,
padding: "10px 12px",
boxSizing: "border-box",
width: 280,
height: 35,
"&:hover": {
borderColor: "#1565c0",
},
},
"&.Mui-focused": {
boxShadow: `${alpha(theme.palette.primary.main, 0.25)} 0 0 0 0.2rem`,
borderColor: theme.palette.primary.main,
},
},
}));
<div className={classes.inputfield}>
<InputBase
startAdornment={
<InputAdornment position="start">
<CalendarIcon />
</InputAdornment>
}
/>
</div>`
style to MuiInputBase-root not MuiInputBase-input

How to only give MUI Switch border style when it is checked?

Here is the demo link. Right now I give root a border style. However, I want to remove the border style when the switch is checked. How would I do this? Thanks for the help!
import * as React from "react";
import Switch from "#mui/material/Switch";
import { withStyles } from "#material-ui/core/styles";
const label = { inputProps: { "aria-label": "Switch demo" } };
const CustomSwitch = withStyles({
root: {
width: "40px",
height: "20px",
padding: "0px",
borderRadius: "10px",
marginRight: "8px",
border: "1px solid #606060",
position: "relative"
},
colorSecondary: {
"&.Mui-checked + .MuiSwitch-track": {
backgroundColor: "#05756C"
},
"&.Mui-checked": {
color: "white"
}
},
thumb: {
position: "absolute",
width: "12px",
height: "12px"
},
track: {
backgroundColor: "transparent"
},
switchBase: {
color: "#606060",
"&$checked": {
// color: 'white!important',
}
}
})(Switch);
export default function BasicSwitches() {
return (
<div>
<CustomSwitch {...label} />
</div>
);
}
Remove the border from the parent (SwitchBase) and put it in the track component inside so it can be targeted by CSS selector when the state of the sibling element changes:
root: {
...
// border: '1px solid #606060', // <-------------------- comment this line
},
track: {
backgroundColor: 'transparent',
borderRadius: '10px',
border: '1px solid #606060',
height: 'auto',
opacity: 1,
},
switchBase: {
color: '#606060',
'&.Mui-checked + $track': {
border: 'none',
},
},
Since you're using v5, you shouldn't use withStyles anymore, it is deprecated and will be removed in v6. Here is the equivalent demo in v5 using styled instead.

Button doesn't disappear immediately; need to move mouse during animation using clip-path

I am setting the clipPath property from circle(0%) to circle(100%) using GSAP timeline.
let t1 = useRef();
useEffect(() => {
t1.current = gsap.timeline({
defaults: { duration: 0.5, ease: "Back.easeOut.config(2)" },
});
t1.current.paused(true); //to ensure animation doesn't play immediately
t1.current.to(".overlay", { clipPath: "circle(100%)" });
});
const handleClick = () => {
t1.current.play(); //start the animation
};
const handleClose = () => {
t1.current.reverse(0.2); //reverse the animation from 0.2 seconds
};
Complete React Component code:
import React, { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faWindowClose } from "#fortawesome/free-solid-svg-icons";
export default function GSAPFullScreen() {
let t1 = useRef();
useEffect(() => {
t1.current = gsap.timeline({
defaults: { duration: 0.5, ease: "Back.easeOut.config(2)" },
});
t1.current.paused(true); //to ensure animation doesn't play immediately
t1.current.to(".overlay", { clipPath: "circle(100%)" });
}, []);
const handleClick = () => {
t1.current.play(); //start the animation
};
const handleClose = () => {
t1.current.reverse(0.2); //reverse the animation from 0.2 seconds
};
return (
<>
<div
className="overlay"
style={{
clipPath: "circle(0%)",
width: "100%",
height: "100%",
position: "fixed",
overflowY: "scroll",
overflowX: "hidden",
backgroundColor: "purple",
}}
>
<FontAwesomeIcon
icon={faWindowClose}
size="2x"
style={{
position: "absolute",
top: "2rem",
right: "2rem",
color: "white",
cursor: "pointer",
}}
onClick={handleClose}
/>
<div className="container md" style={{ color: "white" }}>
<br />
<div style={{ fontWeight: "bold" }}>This is an amazing Question</div>
<div>What is your question? Can you guess?</div>
<div>Option 1</div>
<div>Option 2</div>
<div>Option 3</div>
<div>Option 4</div>
</div>
</div>
<div className="container" style={{ height: "100vh" }}>
<div className="flex">
<button className="lg p-1 btn" onClick={() => handleClick()}>
Launch Animation
</button>
</div>
</div>
</>
);
}
Relevant CSS:
.container {
max-width: 1100px; /* Ensures heading is in center beyond 1100px*/
margin: 0 auto; /* Ensures to keep the 1100px container in middle of the screen;
until 1100px it will be on the side and this property will not have any affect*/
overflow: auto; /* This removes the space on the top of the heading which was created because of margin: 10px 0 on h1*/
padding: 0 40px;
}
.btn {
display: inline-block;
padding: 10px 30px;
cursor: pointer;
background: var(--primary-color);
color: #fff;
border: none;
border-radius: 5px;
}
.md {
font-size: 2rem;
}
.lg {
font-size: 3rem;
}
.flex {
display: flex;
justify-content: center; /* aligns along the main axis*/
align-items: center;
height: 100%;
}
.p-1 {
padding: 1rem; /*1 rem is usually 16px depending the size at root*/
}
.btn:hover:enabled{
transform: scale(0.98); /*reduces the size of button a bit*/
}
When the button has the pseudo class :hover a transform will be applied to the element, which means that it the stacking context is changed (see also Stacking without the z-index property).
To fix this you can add z-index: 1 to the overlay class or remove the transform from the :hover class (Not ideal).

React Stripe Elements - set width to auto for iFrame? Elements invisible inside grid and modal

I am trying to build a Stripe form using React Elements, inside of a React Modal, with layout managed by React Grid
<StripeProvider apiKey="stripeApiKey">
<Grid
container
direction="column"
alignItems="center"
justify="center"
style={{ minWidth: '30rem', maxWidth: '100rem' }}
>
<Grid item>
<Grid
container
direction="column"
justify="center"
style={{
backgroundColor: theme.palette.primary.dark,
padding: '73px',
width: '100%'
}}
>
<Elements>
<CardElement />
</Elements>
</Grid>
</Grid>
</Grid>
</StripeProvider>
The above renders the CardElement, but it's set to 1px width. If I manually set the IFrame's width property to auto it completely resolves my problem. How can I set the IFrame's width property for Stripe? (or is this even possible with cross-origin IFrame)
Or if not, how else can I resolve this issue to get the fields to display?
The style for individual elements for React-Stripe has to be passed manually as props. Below is an example from their official react-stripe-elements sample:
Elements
<CardNumberElement
onBlur={handleBlur}
onChange={this.handleChange}
onFocus={handleFocus}
onReady={handleReady}
{...createOptions(this.props.fontSize)}
/>
Function createOptions
const createOptions = (fontSize, padding) => {
return {
style: {
base: {
fontSize,
color: '#424770',
letterSpacing: '0.025em',
fontFamily: 'Source Code Pro, monospace',
'::placeholder': {
color: '#aab7c4',
},
...(padding ? { padding } : {}),
},
invalid: {
color: '#9e2146',
},
},
};
};
css
input,
.StripeElement {
display: block;
margin: 10px 0 20px 0;
max-width: 500px;
padding: 10px 14px;
font-size: 1em;
font-family: 'Source Code Pro', monospace;
box-shadow: rgba(50, 50, 93, 0.14902) 0px 1px 3px, rgba(0, 0, 0, 0.0196078) 0px 1px 0px;
border: 0;
outline: 0;
border-radius: 4px;
background: white;
}

Resources