Search code examples
javascriptreactjsstyled-components

Styled Components do not pass dom attributes


i'm new in styled-components i use it un react and typescript project.

I use a styled component StyledButton which is created with styled.button but when i pass the attribute disabled={true} at my top level component, it is not display in the dom render. The style is well render (when disable button is grey) but the prop disabled is not pass to the dom element button (so it's still clickable...)

Button.style.ts:

import styled from 'styled-components';
import { fontFamily, fontSize, fontWeight, getSpacing } from '../../stylesheet';

interface StyledButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
  fullWidth?: boolean;
  backgroundColor: string;
  textColor: string;
  borderColor?: string;
  borderRadiusProp: string;
}

export const StyledButton = styled.button<StyledButtonProps>(props => ({
  cursor: 'pointer',
  height: '45px',
  borderRadius: props.borderRadiusProp,
  ...((props.fullWidth ?? false) && {
    width: '100%',
  }),
  padding: '12px 24px',
  color: props.textColor,
  background: props.backgroundColor,
  textAlign: 'center',
  ...(props.borderColor ?? ''
    ? {
        borderWidth: 1,
        borderColor: props.borderColor,
      }
    : {
        border: 'none',
      }),
  ':hover': {
    backgroundColor: props.backgroundColor,
  },
}));

export const ButtonContent = styled.div`
  height: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  font-family: ${fontFamily.main};
  font-size: ${fontSize.medium};
  font-weight: ${fontWeight.large};
  margin-right: ${getSpacing(4)};
  margin-left: ${getSpacing(4)};
`;

Button.tsx :

import React from 'react';
import { borderRadius } from 'stylesheet';
import { ButtonContent, StyledButton } from './Button.style';

export interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
  fullWidth?: boolean;
  borderRadiusProp?: string;
  backgroundColor: string;
  textColor: string;
  borderColor?: string;
  disabled?: boolean;
  children: React.ReactNode;
}

const Button = ({
  onClick,
  fullWidth,
  borderRadiusProp = borderRadius.m,
  backgroundColor,
  textColor,
  borderColor,
  disabled = false,
  children,
}: ButtonProps): JSX.Element => {
  return (
    <StyledButton
      disabled={disabled}
      onClick={onClick}
      fullWidth={fullWidth}
      borderColor={borderColor}
      borderRadiusProp={borderRadiusProp}
      backgroundColor={backgroundColor}
      textColor={textColor}
    >
      <ButtonContent>{children}</ButtonContent>
    </StyledButton>
  );
};

export default Button;

GradientButton.tsx:

import Button from 'components/Button/Button';
import React from 'react';
import { borderRadius, colorUsage, gradientColors } from 'stylesheet';

interface GradientButtonProps extends React.HTMLProps<HTMLButtonElement> {
  fullWidth?: boolean;
  children: React.ReactNode;
  disabled?: boolean;
  gradient?: keyof typeof gradientColors;
}

export const getColorBackground = (gradients: string[], disabled?: boolean): string => {
  if (disabled ?? false) return colorUsage.buttonDisabled;
  return `linear-gradient(90deg, ${gradients[0]} -27.6%, ${gradients[1]} 111.77%);`;
};

export const getTextColor = (disabled?: boolean): string => {
  if (disabled ?? false) return colorUsage.buttonDisabledText;
  return colorUsage.buttonPrimaryTextColor;
};

const GradientButton = ({
  children,
  gradient = 'blue',
  disabled = false,
  ...rest
}: GradientButtonProps): JSX.Element => {
  const backgroundGradient = getColorBackground(gradientColors[gradient], disabled);
  const textColor = getTextColor(disabled);

  return (
    <Button
      borderRadiusProp={borderRadius.s}
      backgroundColor={backgroundGradient}
      textColor={textColor}
      disabled={disabled}
      {...rest}
    >
      {children}
    </Button>
  );
};

export default GradientButton;

file where i call my button:

  <GradientButton
      id="login-form-button"
      gradient="blue"
      type="submit"
      disabled={!isValid || isEmpty(touched)}
      fullWidth
   >
       Login
   </GradientButton>

Solution

  • Like you mentioned with the disabled set to true (hardcoded) it works, this means button is rendered correctly, the issue seems to be with

    disabled={!isValid || isEmpty(touched)}

    The condition might never evaluate to true hence the button is never disabled. Recheck this condition and it should work as expected.