Styled Components - two different elements with the same styles
Asked Answered
L

4

7

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.

Luetic answered 30/4, 2020 at 8:31 Comment(0)
S
15

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*/
`;
Sabian answered 30/4, 2020 at 8:55 Comment(2)
How can u get props in the mass style block?Daffie
@MoteZart https://mcmap.net/q/265658/-idiomatic-way-to-share-styles-in-styled-components has the solutionOverexert
B
0

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);
Burtburta answered 20/8, 2021 at 18:26 Comment(1)
If you use css`` as mentioned in Joe's answer, it will take care of this for you. That answer does not show a raw template string literal.Harrier
N
0

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>
    )
Nearby answered 30/9, 2023 at 13:37 Comment(0)
H
0

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.

Harrier answered 27/2, 2024 at 20:16 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.