rwacarter
rwacarter

Reputation: 2004

Styled Components - two different elements with the same styles

I have a Button component (in React) which can either be a button or an a element, depending on if a href prop is passed to the component. Something similar to below:

const Button = ({ children, href, onClick }) => {
    if(href) {
        return <a href={href} onClick={onClick}>{children}</a>;
    }

    return <button type="button" onClick={onClick}>{children}</button>;
};

I previously used Sass to style these components, but am now attempting to move over to styled-components. However, I have come across an issue where these two elements require the same styles, but the syntax of styled-components would require me to create to separate variables - styled.button and styled.a, with duplicated styles for each.

I was wondering if there was a way of dynamically changing the element used in styled-components, maybe based on props in the same way one can change individual CSS properties? I have attempted something along the lines of:

const StyledButton = styled((props) => props.href ? 'a' : 'button')`
    ...
`;

but no luck so far. Any advice would be greatly appreciated.

Upvotes: 7

Views: 11264

Answers (4)

coppereyecat
coppereyecat

Reputation: 213

As in the other answers, you can create generic styles for this component, but from v4+, you can also use the as property to make a single component polymorphic. (See polymorphic prop in Styled's documentation).

An example of this:

const SomeButton = styled.button`
  border: red 1px solid;
`

function UsingSomeButtonAsALink(href) {
  return <SomeButton as={'a'} href={href}>Text</SomeButton>
}

In older versions of Styled, there was a similar polymorphic ability via the .withComponent API, but this was deprecated in v4 and removed completely in v6. The documentation no longer describes how to use this API.

Upvotes: 0

Danila_L
Danila_L

Reputation: 1

Using the css helper is only justified when interpolating a function, not a string. In your case, it is more reasonable to use the polymorphic props as:

const Title = styled.h1`
      ...
    `;

    return (
      <Title>Some title</Title>
      <Title as='h2'>Some another title</Title>
    )

Upvotes: 0

Soufiane Boutahlil
Soufiane Boutahlil

Reputation: 2604

I tried Joe Lloyd's answer but it didn't work because the function styled.xxx() takes one parameter of type templateStringsArray instead of template String:

const buttonStyles = [
`
color: red;
...
`
]

const StyledA = styled.a(buttonStyles);
const StyledButton = styled.button(buttonStyles);

Upvotes: 0

Joe Lloyd
Joe Lloyd

Reputation: 22323

Create generic styles that you can reuse

You can extract and pass styles as string args to a styled component.

const buttonStyles = `
color: red;
...
`

const StyledA = styled.a(buttonStyles);
const StyledButton = styled.button(buttonStyles);

If you need some exceptions

import styled, { css } from ‘styled-components’;

const baseInputStyles = css`
  padding: 0.5em;
`;

const StyledA = styled.a`
  ${baseInputStyles}
`;

const StyledButton = styled.button`
  ${baseInputStyles}
  /* make changes as needed*/
`;

Upvotes: 15

Related Questions