I have setup and published to a private server a StoryBook design system using ThemeUI that contains components. One such component is the button shown below.
import React, { FC } from "react";
import { Button as ButtonUI, SxStyleProp } from "theme-ui";
export const Button: FC<ButtonProps> = ({ onClick, children, variant, sx, disabled, onMouseOver, onMouseOut }) => {
return (
<ButtonUI
disabled={disabled || false}
variant={variant || "primary"}
onClick={onClick}
sx={{...sx}}
onMouseOver={onMouseOver || (() => {})}
onMouseOut={onMouseOut || (() => {})}
>
{children}
</ButtonUI>
);
};
export type ButtonProps = {
/**
* The action to perform when the button is clicked
*/
onClick: () => void;
/**
* The contents of the button
*/
children?: any;
/**
* The type of button
*/
variant?: string;
/**
* custom styles for the button
*/
sx?: SxStyleProp;
/**
* If the button is disabled
*/
disabled?: boolean;
/**
* The action to perform if the mouse moves over the button
*/
onMouseOver?: () => void;
/**
* The action to perform if the mouse moves off the button
*/
onMouseOut?: () => void;
};
Button.defaultProps = {
variant: "primary",
disabled: false
};
When I import this component into my React App in a separate project the component renders but all properties in the sx prop are ignored...
/** @jsx jsx */
import { Flex, jsx } from "theme-ui";
import Modal from "../Modal";
import { Button } from "<<<PRIVATE SERVER>>>";
/**
* Renders a popup the gives the player the option to logout
* @param title the heading of the modal
* @param confirmString the text for the confirm button
* @param cancelString the text for the cancel button
* @param confirmAction the action to perform when the user confirms
* @param cancelAction the action to perform when the user cancels
*/
export default function LogoutModal({ title, confirmString, cancelString, confirmAction, cancelAction }: Props) {
return (
<Modal
title={title}
closeAction={cancelAction}
children={
<Flex>
<Button
onClick={confirmAction}
sx={{
mr: 1
}}
variant="negative">{confirmString}</Button>
<Button
onClick={cancelAction}
sx={{
ml: 1
}}
variant="secondary">{cancelString}</Button>
</Flex>
}
/>
);
}
interface Props {
title: string;
confirmString: string;
cancelString: string;
confirmAction: () => void;
cancelAction: () => void;
}
So the button renders but without the applicable margin (or any other styles I add in the sx prop. Does anyone have any idea why this would be the case?
Interestingly if I call the component somewhere else in Storybook (rather than when imported into a seperate project) the sx prop works as expected.
TL;DR
sxgets transformed to aclassNameby theme-uiSee the working CodeSandbox demo, then continue reading.
From the documentation:
Use the pragma on every file
So it's first needed to have the pragma comment at the top of the file, and import the right
jsxfunction:The
sxprop isn't passed down to the component, it's in fact converted to CSS and aclassNameis auto-generated and applied to the component.Pass down the
classNameSo if you'd like the parent component applying custom style to the
Buttoncomponent via thesxprop, you need to pass down theclassNameprop.Personal recommendation is to not use some kind of hack passing down
sxcontent down. I've been working on a huge project professionally that uses theme-ui and never have we ever needed anything else than pass theclassNamedown to merge styles automatically.