In short, styled-components
generates a className
that must be applied to an HTML/JSX Element
in order to see styles. In addition, the composed component must be an instance of a styled component. My example here explains a basic approach to styling a custom component.
Since, I don't have your full code, I recreated the example from the video you linked.
Working example (in this case, I'm styling TabContent
within Tab
and altering its svg
element):

In addition, I structured my files like so, which avoids the import recursion issues:
├── src
| ├── components
| | ├── Tab
| | | ├── Tab.js
| | | └── index.js
| | |
| | ├── TabContent
| | | ├── TabContent.js
| | | └── index.js
| | |
| | ├── TabList
| | | └── index.js
| | |
| | ├── TabPanel
| | | └── index.js
| | |
| | ├── TabPanels
| | | ├── TabPanels.js
| | | └── index.js
| | |
| | └── Tabs
| | └── index.js
| └── index.js
|
├── index.js
└── tabs.js
src/components/Tab/Tab.js
import React from "react";
import PropTypes from "prop-types";
const Tab = ({ children, className, disabled, onSelectTab }) => (
<div className={className} onClick={disabled ? null : onSelectTab}>
{children}
</div>
);
Tab.propTypes = {
className: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
disabled: PropTypes.bool,
onSelectTab: PropTypes.func.isRequired
};
export default Tab;
src/components/Tab/index.js
import styled from "styled-components";
import Tab from "./Tab";
import TabContent from "../TabContent";
export default styled(Tab)`
display: inline-block;
padding: 10px;
margin: 10px;
border-bottom: 2px solid;
border-color: rgba(0, 0, 0, 0.65);
color: rgba(0, 0, 0, 0.65);
cursor: pointer;
-webkit-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
${({ disabled, isActive }) => {
if (disabled) return `opacity: 0.25; cursor: default;`;
if (isActive) return `color: #1890ff; border-bottom-color: #1890ff;`;
}}
&:hover {
color: #40a9ff;
border-bottom-color: #40a9ff;
${({ disabled }) =>
disabled &&
`color: rgba(0, 0, 0, 0.65); border-bottom-color: rgba(0, 0, 0, 0.65);`};
}
${TabContent} {
& svg {
font-size: 13px;
}
}
`;
src/components/TabContent/TabContent.js
import React from "react";
import PropTypes from "prop-types";
const TabContent = ({ children, className }) => (
<div className={className}>{children}</div>
);
TabContent.propTypes = {
className: PropTypes.string.isRequired,
children: PropTypes.node.isRequired
};
export default TabContent;
src/components/TabContent/index.js
import styled from "styled-components";
import TabContent from "./TabContent";
export default styled(TabContent)`
font-size: 20px;
`;
src/components/TabList/index.js
import { Children, cloneElement, useCallback } from "react";
import PropTypes from "prop-types";
const TabList = ({ activeIndex, children, setActiveIndex }) => {
const handleSelectedTab = useCallback(
index => {
setActiveIndex(index);
},
[setActiveIndex]
);
return Children.map(children, (child, index) =>
cloneElement(child, {
isActive: activeIndex === index,
onSelectTab: () => handleSelectedTab(index)
})
);
};
TabList.propTypes = {
activeIndex: PropTypes.number,
children: PropTypes.node.isRequired,
setActiveIndex: PropTypes.func
};
export default TabList;
src/components/TabPanel/index.js
import PropTypes from "prop-types";
const TabPanel = ({ children }) => children;
TabPanel.propTypes = {
children: PropTypes.node.isRequired
};
export default TabPanel;
src/components/TabPanels/TabPanels.js
import React, { Children } from "react";
import PropTypes from "prop-types";
const TabPanels = ({ activeIndex, children, className }) => (
<div className={className}>{Children.toArray(children)[activeIndex]}</div>
);
TabPanels.propTypes = {
activeIndex: PropTypes.number,
children: PropTypes.node.isRequired,
setActiveIndex: PropTypes.func
};
export default TabPanels;
src/components/TabPanels/index.js
import styled from "styled-components";
import TabPanels from "./TabPanels";
export default styled(TabPanels)`
padding: 10px;
`;
src/components/Tabs/Tabs.js
import { Children, cloneElement, useState } from "react";
import PropTypes from "prop-types";
import TabPanels from "../TabPanels";
import TabList from "../TabList";
const Tabs = ({ children }) => {
const [activeIndex, setActiveIndex] = useState(0);
return Children.map(children, child => {
switch (child.type) {
case TabPanels: {
return cloneElement(child, { activeIndex });
}
case TabList: {
return cloneElement(child, {
activeIndex,
setActiveIndex
});
}
default: {
return child;
}
}
});
};
Tabs.propTypes = {
children: PropTypes.node.isRequired
};
export default Tabs;
src/components/index.js
export { default as Tab } from "./Tab";
export { default as TabContent } from "./TabContent";
export { default as TabList } from "./TabList";
export { default as TabPanel } from "./TabPanel";
export { default as TabPanels } from "./TabPanels";
export { default as Tabs } from "./Tabs";
src/index.js
import React from "react";
import ReactDOM from "react-dom";
import {
Tab,
TabContent,
Tabs,
TabList,
TabPanels,
TabPanel
} from "./components";
import tabs from "./tabs";
const App = () => (
<Tabs>
<TabList>
{tabs.map(({ icon, title, disabled }) => (
<Tab key={title} disabled={disabled}>
<TabContent>
{icon} {title}
</TabContent>
</Tab>
))}
</TabList>
<TabPanels>
{tabs.map(({ title, content }) => (
<TabPanel key={title}>{content}</TabPanel>
))}
</TabPanels>
</Tabs>
);
ReactDOM.render(<App />, document.getElementById("root"));
src/tabs.js
import React from "react";
import { FaAppleAlt, FaCarrot, FaLemon } from "react-icons/fa";
export default [
{
title: "Apples",
icon: <FaAppleAlt />,
content: <p>Apples are delicious.</p>
},
{
title: "Carrots",
icon: <FaCarrot />,
content: <p>Carrots are nutritious.</p>,
disabled: true
},
{
title: "Lemons",
icon: <FaLemon />,
content: <p>Lemons are ubiquitous.</p>
}
];