A time ago I had to build a subscription form using the Spreedly iFrame API to allow a user to use its credit card in a safe way.
After a while, I found myself into an issue with the card number and the CVV number inputs because Spreedly inserts an iframe
; therefore the inputs are not under my control (and my CSS).
The easy solution
Fortunately, Spreedly accepts a style inline string via the setStyle
function.
Spreedly.on("ready", () => {
Spreedly.setStyle("number", "width:225px; height:35px;");
});
This is a little bit ugly but it's a solution after all. Let's see how to improve this...
Using the theme with strings
We can use the useTheme
hook to get all the tokens we defined in the theme.
import {useEffect} from 'react'
import {useTheme} from "@chakra-ui/react"
const buildStyles = theme => `
border: 2px solid ${theme.colors.gray[300]},
color: ${theme.colors.black},
lineHeight: ${theme.sizes[5]}
`
const MyComp = () => {
const theme = useTheme();
useEffect(() => {
Spreedly.on("ready", () => {
Spreedly.setStyle("number", buildStyles(theme));
});
}, []);
return <>...</>;
};
This is similar to styled-components
because of the string templates usage to create styles.
💡 Tip: remember that your component should be wrapped by a ChakraProvider
to get the theme
object.
Using a CSS object
I looked for a nicer way to handle a CSS object in JavaScript instead of using one big string. Chakra UI uses emotion under the hook to build the CSS classes, so I found this solution:
import {css} from "@chakra-ui/react"
import {serializeStyles} from '@emotion/serialize'
const toCSSString = (styles, theme) => serializeStyles([css(styles)(theme)]).styles;
The serializeStyles
function from emotion
convert an object into another one built with a name
attribute for an auto-generated CSS class name; and the styles
attribute with all the style properties in one string. 😁
The css
function from Chakra UI normalizes the shortcuts that Chakra provides like:
<Box w="full" h={9} bg="blue.300"/>
The w
, h
and bg
are aliases for width
, height
and background
style properties. The props
for this Box
component are passed to the css
getting this output:
{
height: "var(--chakra-sizes-9)",
background: "var(--chakra-colors-blue-300)",
width: "var(--chakra-sizes-full)"
}
Here we can't use nice values like 9
, full
or blue.300
because Spreedly is inside an iframe
and our CSS custom properties (a.k.a. CSS variables) are not in the scope of the iframe
's stylesheet.
Building the inline styles from an object
We are going to put them all together to get the final theme values (not the custom properties) and serialize the CSS object into a inline style string using emotion
.
import {css, useTheme} from "@chakra-ui/react"
import {serializeStyles} from '@emotion/serialize'
const buildStyles = theme => ({
border: `2px solid ${theme.colors.gray[300]}`,
color: theme.colors.black,
lineHeight: theme.sizes[5]
});
const toCSSString = (styles, theme) => serializeStyles([css(styles)(theme)]).styles;
const MyComp = () => {
const theme = useTheme();
useEffect(() => {
Spreedly.on("ready", () => {
Spreedly.setStyle(
"number",
toCSSString(buildStyles(theme), theme)
);
});
}, []);
return <>...</>;
};
Conclusion
I hope these internals functions from Chakra UI and emotion help you when using Spreedly, an iframe, or a UI component where you can't send the styles in the cool way that Chakra provides.
Top comments (0)