stylex: `StyleXStyles` type error for styles that use variables

The problem

While implementing styles in components using StyleXStyles, as outlined in the documentation, I’m encountering a TypeScript error with styles that include variables. The error is as follows:

Type 'Readonly<{ readonly position: StyleXClassNameFor<"position", "absolute">; readonly top: StyleXClassNameFor<"top", 0>; readonly zIndex: StyleXClassNameFor<"zIndex", 90>; readonly right: StyleXClassNameFor<...>; readonly opacity: StyleXClassNameFor<...>; readonly pointerEvents: StyleXClassNameFor<...>; }>' is not assignable to type 'StyleXStyles | undefined'.
  Type 'Readonly<{ readonly position: StyleXClassNameFor<"position", "absolute">; readonly top: StyleXClassNameFor<"top", 0>; readonly zIndex: StyleXClassNameFor<"zIndex", 90>; readonly right: StyleXClassNameFor<...>; readonly opacity: StyleXClassNameFor<...>; readonly pointerEvents: StyleXClassNameFor<...>; }>' is not assignable to type 'Readonly<Readonly<{ readonly theme?: StyleXClassNameFor<"theme", Readonly<string | null | undefined>> | undefined; readonly MozOsxFontSmoothing?: StyleXClassNameFor<"MozOsxFontSmoothing", Readonly<...>> | undefined; ... 534 more ...; readonly '::-webkit-search-results-decoration'?: StyleXClassNameFor<...> | undefine...'.
    Types of property 'opacity' are incompatible.
      Type 'StyleXClassNameFor<"opacity", string>' is not assignable to type 'StyleXClassNameFor<"opacity", Readonly<number | all | undefined>> | undefined'.
        Type 'StyleXClassNameFor<"opacity", string>' is not assignable to type 'StyleXClassNameFor<"opacity", Readonly<number | all | undefined>>'.ts(2322)
button.tsx(8, 3): The expected type comes from property 'style' which is declared here on type 'IntrinsicAttributes & ButtonStyles'
(property) ButtonStyles.style?: x.StyleXStyles | undefined

This issue arises when attempting to pass styles, which include CSS variables, to a component.

How to reproduce

Steps to reproduce:

  1. Define a component that accepts a style prop, as per the documentation:
interface ButtonProps extends Omit<ComponentProps<"button">, "className" | "style"> {
  style?: StyleXStyles;
}

function Button({ style, ...props }: ButtonProps) {
  return <button {...props} {stylex.props(styles.base, style)} />;
}
  1. In a separate component, define a style that typically uses a numeric value but uses a variable in this case:
// tokens.stylex.ts
const tokens = stylex.defineVars({
  opacity: '0',
});

// my-component.tsx
const styles = stylex.create({
  devicesButton: {
    opacity: tokens.opacity,
  },
};

function MyComponent() {
  return <Button style={styles.devicesButton} />;
}
  1. Notice the TypeScript error on the style prop, which indicates a mismatch in the expected type for the ‘opacity’ property.

Expected behavior

The style prop should be compatible with the properties accepted by stylex.props. I propose that the type definition might be more accurately defined as:

style?: StyleXArray<
      | (null | undefined | CompiledStyles)
      | boolean
      | Readonly<[CompiledStyles, InlineStyles]>
    >

If this is the correct definition, it would be beneficial to have the relevant types (CompiledStyles, InlineStyles, and StyleXArray) made available for import (and the documentation updated). Alternatively, StyleXStyles could be updated to reflect this structure.

Looking forward to your suggestions or updates regarding this matter. Thank you for your assistance.

About this issue

  • Original URL
  • State: closed
  • Created 5 months ago
  • Comments: 15 (14 by maintainers)

Most upvoted comments

Ah yes. You are absolutely right, I updated my codesandbox to use :hover instead and can now see the difference. Thank you for explaining!

Thanks guys!

Hi @nmn ! How about we merge the current PR, close this ticket, and I come up with a follow-up PR later for the possible remaining properties (as at first glance, a lot of them already supports string values)?

@nmn should I complete my PR for the remaining properties?

@nmn Looking at the solution from @yousoumar , I’m wondering if we need to make all property be able to receive a string? Any property can be assigned a css custom property which would be a string, right?

@yousoumar Yes. That’s it. Happy to accept a PR.

I would wanna work on this if possible @nmn. I was looking for it in the codebase. Is it line 479 in packages/stylex/src/StyleXCSSTypes.js?