Up to this point I have only used AI to generate code snippets, either via Gemini web or the Codeium extension on VS Code/Rider. Recently, I decided to give Trae AI IDE a try and as I was updating my portfolio site at esausilva.dev, a brilliant idea sparked and found a use-case to fully utilize the power of AI. That is when I had my AHA moment, my AI enlightening moment.
In the process of upgrading React, Gatsby and the rest of the packages, one particular package hasn’t been updated in 7 years (at the time of this writing) and has a dependency on React 16 and giving me dependency issues with newer React version.
What is this library? react-web-tabs. I have a tabbed section in my portfolio site with some of my open source projects. So I decided to nuke the library and either use another one or write my own tabs code.
Trae to the rescue
But, this is when it hit me. There are engineers generating complete apps with the help of AI IDEs like Cursor. So why not fully utilize Trae’s chat and try to generate a new React component with tabs functionality?
My first prompt was Create a React component with vertical tab
. Very vague, I know, but I don’t have much experience with prompt engineering.
The result? Although, correct implementation, not ideal. It gave me a component that accepts a list of items and displays them in a tabbed manner, utilizing the same library I’m trying to remove.
I see you're interested in creating a React component with vertical tabs. Looking at your current code in OpenSource.js , you already have a good implementation using react-web-tabs. Here's a simplified example of how to create a similar vertical tabs component:
Now the follow up prompt: Do not use a library
. Again, very much vague. However, this time I was blown away.
I'll help you create a custom vertical tabs component without using external libraries. Here's a replacement for your current OpenSource component that implements tabs from scratch:
It gave me back my own component, OpenSource.js
, but refactored with a tabs implementation from scratch. Keeping the same content in my component, same styling and same functionality!!! I didn’t mention I wanted to refactor this specific component, the IDE just knew and I was a happy camper.
And the AI closing comments:
Key changes made: 1. Removed the react-web-tabs dependency 2. Created custom styled components for the tab structure 3. Implemented tab switching using React state 4. Maintained the same responsive behavior and styling approach 5. Added proper accessibility attributes and keyboard navigation The component now uses a simple state management approach with activeTab to control which content is displayed. The styling is similar to your original implementation but with pure CSS/styled-components. The tabs are now regular buttons which is better for accessibility, and the active state is managed through a className.
There are some minor differences in styling, but nothing I cannot readd myself.
Show me the pudding
My original component:
import React, { useEffect, useState } from 'react'; import styled from 'styled-components'; import { Tabs, Tab, TabPanel, TabList } from 'react-web-tabs'; import { HeadingWrapper } from './styles/HeadingWrapper'; import { openSource } from '../data'; import 'react-web-tabs/dist/react-web-tabs.css'; const TabsCustom = styled(Tabs)` margin: 1em 0 1.5em 0; `; const TabListCustom = styled(TabList)` max-width: 60px; @media (min-width: ${({ theme }) => theme.media.medium}) { max-width: 450px; } `; const TabCustom = styled(Tab)` color: ${({ theme }) => theme.colors.blueish}; font-weight: bolder; &[aria-selected='true']:after { border-right: 3px solid ${({ theme }) => theme.colors.blueish} !important; } `; const OpenSource = () => { const [innerWidth, setInnerWidth] = useState(0); useEffect(() => { if (typeof window !== `undefined`) { setInnerWidth(window.innerWidth); } }, []); return ( <> <HeadingWrapper id="nav-oss"> <h1>Open Source</h1> </HeadingWrapper> <p> These are some of my open source projects. Visit my GitHub{' '} <a href="https://github.com/esausilva" target="_blank" rel="noopener noreferrer" > profile </a>{' '} to see the rest of my repos. </p> <div> <TabsCustom defaultTab="0" vertical> <TabListCustom> {openSource.map((project, idx) => ( <TabCustom tabFor={`${idx}`} key={`${project.project}-tab`}> {innerWidth <= 767 ? idx + 1 : project.project} </TabCustom> ))} </TabListCustom> {openSource.map((project, idx) => ( <TabPanel tabId={`${idx}`} key={`${project.project}-panel`}> <h2>{project.project}</h2> <p>{project.description}</p> <p> <em>{project.stack}</em> </p> <p> <a href={project.link} target="_blank" rel="noopener noreferrer" > Repo Link </a> </p> </TabPanel> ))} </TabsCustom> </div> </> ); }; export { OpenSource };
Trae’s refactor:
import React, { useEffect, useState } from 'react'; import styled from 'styled-components'; import { HeadingWrapper } from './styles/HeadingWrapper'; import { openSource } from '../data'; const TabContainer = styled.div` display: flex; margin: 1em 0 1.5em 0; `; const TabList = styled.div` max-width: 60px; border-right: 1px solid ${({ theme }) => theme.colors.blueish}; @media (min-width: ${({ theme }) => theme.media.medium}) { max-width: 450px; } `; const Tab = styled.button` width: 100%; padding: 1rem; border: none; background: none; text-align: left; cursor: pointer; color: ${({ theme }) => theme.colors.blueish}; font-weight: bolder; position: relative; &.active { &:after { content: ''; position: absolute; right: -1px; top: 0; height: 100%; width: 3px; background: ${({ theme }) => theme.colors.blueish}; } } `; const TabPanel = styled.div` padding: 0 2rem; flex: 1; `; const OpenSource = () => { const [activeTab, setActiveTab] = useState(0); const [innerWidth, setInnerWidth] = useState(0); useEffect(() => { if (typeof window !== `undefined`) { setInnerWidth(window.innerWidth); } }, []); return ( <> <HeadingWrapper id="nav-oss"> <h1>Open Source</h1> </HeadingWrapper> <p> These are some of my open source projects. Visit my GitHub{' '} <a href="https://github.com/esausilva" target="_blank" rel="noopener noreferrer" > profile </a>{' '} to see the rest of my repos. </p> <TabContainer> <TabList> {openSource.map((project, idx) => ( <Tab key={`${project.project}-tab`} className={activeTab === idx ? 'active' : ''} onClick={() => setActiveTab(idx)} > {innerWidth <= 767 ? idx + 1 : project.project} </Tab> ))} </TabList> <TabPanel> <h2>{openSource[activeTab].project}</h2> <p>{openSource[activeTab].description}</p> <p> <em>{openSource[activeTab].stack}</em> </p> <p> <a href={openSource[activeTab].link} target="_blank" rel="noopener noreferrer" > Repo Link </a> </p> </TabPanel> </TabContainer> </> ); }; export { OpenSource };
Final thoughts
I will definitely attempt to polish my AI prompting skills and exploring more on having the AI generate entire components other than just code snippets.
You can find the component at: https://github.com/esausilva/esausilva-dev/blob/master/src/components/OpenSource.js
If you liked this reading, share it on your social media and you can follow me on Twitter or LinkedIn.
Consider giving back by getting me a coffee (or a couple) by clicking the following button: