question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Is it possible to extend a component and modify functional behavior while maintaining the component API?

See original GitHub issue

Basically, I want to extend a components styles and include all the API behavior of a styled-component (as prop, string interpolation, etc), but add some functional differences to the render function.

Example

Simple style-only extension works just fine:

const Button = styled.button`
  border: 1px solid gray;
  background-color: lightgray;
`;

const BlueButton = styled(Button)`
  border-color: darkblue;
  background-color: lightblue;
`;

I can use BlueButton with an anchor tag using the as prop: <BlueButton as="a">.

What if I want to modify the render behavior as well?

let IconButton = ({ iconClass, children, ...props }) => (
  <Button {...props}>
    <i className={iconClass} /> {children}
  </Button>
);

IconButton = styled(IconButton)`
  i {
    height: 30px;
    width: 30px;
    margin-right: 5px;
  }
`;

The above captures the styling, but breaks when using the as prop. I would love to still be able to do <IconButton as="a">. I’m not sure if there is a pattern that will allow me to do this.

Live Example

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:18 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
diondiondioncommented, Mar 17, 2019

Related feature request: #2129

Basically, we need a way to tell styled-components to ignore the as prop and just pass it on to the wrapped component.

In your example, it would then be passed on to the Button component and everything would work as expected again. To visualise this here’s an example of the prop being passed down explicitly:

let IconButton = ({ iconClass, as, children, ...props }) => (
  <Button {...props} as={as}>
    <i className={iconClass} /> {children}
  </Button>
);

Unfortunately, the request wasn’t received very well by the s-c team so far.

2reactions
stonebkcommented, Jun 28, 2019

What are the drawbacks to following the same pattern that React did with refs?

import { forwardAs } from 'styled-components';

const Button = styled.button`
    /* styles */
`;

const IconButton = forwardAs((props, as) => (
  <Button as={as} {...props}>
    <Icon>{icon}</Icon>
    {children}
  </Button>
))`
    /* icon button styles */
`;

It seems like we already have a well-established pattern for handling these types of props in React, why wouldn’t we just follow that pattern?

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Override Existing React Components | Pluralsight
To override a style, you have two options. Either you can pass a style object, or you can pass a function that will...
Read more >
How To Extend Classes with Angular Component Inheritance
Learn how to use the power of inheritance to extend your Angular components with common functionality.
Read more >
How to extend / inherit components? - angular - Stack Overflow
Just use inheritance, extend parent class in child class and declare constructor with parent class parameter and this parameter use in ...
Read more >
Reusable Components in React — A Practical Guide
How to design reusable React components and reuse them across projects and apps. Learn more about best practices with fragments, props, ...
Read more >
React.Component
The render() method is the only required method in a class component. When called, it should examine this.props and this.state and return one...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found