How to extend CoreUI components in React
Extending components is a fundamental requirement when building a consistent design system or a large-scale enterprise application. With over 25 years of experience in software development and as the creator of CoreUI, I’ve designed our React components to be inherently flexible and easy to wrap. The most efficient and modern solution to extend CoreUI components is to use the “Wrapper Pattern,” which involves creating a custom functional component that spreads its props onto the underlying CoreUI primitive. This approach ensures you maintain full access to the original API while adding your own custom styles, default behaviors, or business logic.
Use the React wrapper pattern and prop spreading to extend CoreUI components while preserving their original functionality.
import React, { forwardRef } from ‘react’
import { CButton } from ‘@coreui/react’
const MyExtendedButton = forwardRef(({ children, ...props }, ref) => {
return (
<CButton ref={ref} color=’primary’ variant=’outline’ {...props}>
{children}
</CButton>
)
})
MyExtendedButton.displayName = ‘MyExtendedButton’
export default MyExtendedButton
Extending components in React allows you to create a specialized version of a generic UI element. By using forwardRef, you ensure that the extended component works seamlessly with ref-based logic like focus management, tooltips, and libraries like react-hook-form. The spread operator (...props) passes all standard CoreUI Button props—like onClick, disabled, or type—down to the internal component automatically. This method is preferred over modifying the source code because it keeps your application decoupled from the library’s internal implementation, making future updates much easier.
Extending Buttons with Custom Styles
When building a specific theme, you often need a button that always carries a particular set of classes or styles. This example shows how to merge your local styles with CoreUI’s CButton.
import React, { forwardRef } from 'react'
import { CButton } from '@coreui/react'
const BrandingButton = forwardRef(({ className, style, children, ...rest }, ref) => {
// We merge custom branding classes with any classes passed via props
const combinedClasses = `my-company-btn ${className || ''}`
// Merge default branding styles with any styles passed via props
const mergedStyles = { borderRadius: '20px', fontWeight: 'bold', ...style }
return (
<CButton
ref={ref}
className={combinedClasses}
style={mergedStyles}
{...rest}
>
{children}
</CButton>
)
})
BrandingButton.displayName = 'BrandingButton'
export default BrandingButton
Creating a Specialized Currency Input
You can extend form controls to include specific formatting logic. For instance, creating a specialized input that leverages a helper to format a number as currency while using the CoreUI Form Control.
import React from 'react'
import { CFormInput, CInputGroup, CInputGroupText } from '@coreui/react'
const CurrencyInput = ({ label, value, ...props }) => {
// In a real scenario, you might use a currency formatter here
// Reference: /answers/how-to-format-a-number-as-currency-in-javascript/
return (
<CInputGroup className='mb-3'>
<CInputGroupText>$</CInputGroupText>
<CFormInput
type='number'
placeholder='0.00'
aria-label={label}
value={value}
{...props}
/>
</CInputGroup>
)
}
export default CurrencyInput
Wrapping Modals for Consistent Layouts
Modals often require a specific header and footer structure across an entire app. Wrapping the CoreUI Modal allows you to define this structure once.
import React from 'react'
import {
CModal,
CModalHeader,
CModalTitle,
CModalBody,
CModalFooter,
CButton
} from '@coreui/react'
const AppModal = ({ visible, onClose, title, children, ...props }) => {
return (
<CModal visible={visible} onClose={onClose} alignment='center' {...props}>
<CModalHeader onClose={onClose}>
<CModalTitle>{title}</CModalTitle>
</CModalHeader>
<CModalBody>
{children}
</CModalBody>
<CModalFooter>
<CButton color='secondary' onClick={onClose}>
Cancel
</CButton>
<CButton color='primary'>Confirm Action</CButton>
</CModalFooter>
</CModal>
)
}
export default AppModal
Extending Badges with Automatic Text Transformation
Sometimes you want a component to automatically handle data normalization. Here we extend the CoreUI Badge to ensure text is always uppercase.
import React from 'react'
import { CBadge } from '@coreui/react'
const StatusBadge = ({ status, ...props }) => {
// We transform the string to uppercase for visual consistency
// Reference: /answers/how-to-convert-a-string-to-uppercase-in-javascript/
const label = typeof status === 'string' ? status.toUpperCase() : status
const getColor = (val) => {
if (val === 'ACTIVE') return 'success'
if (val === 'PENDING') return 'warning'
return 'danger'
}
return (
<CBadge color={getColor(label)} {...props}>
{label}
</CBadge>
)
}
export default StatusBadge
Enhanced Navigation Components
You can extend the CoreUI Sidebar or Nav components to automatically handle active states based on your routing logic or permissions.
import React from 'react'
import { CNavItem, CBadge } from '@coreui/react'
const PermissionNavItem = ({ userRole, requiredRole, children, ...props }) => {
// If the user doesn't have the required role, we don't render the item
if (userRole !== requiredRole) {
return null
}
return (
<CNavItem {...props}>
{children}
<CBadge color='info' className='ms-auto'>NEW</CBadge>
</CNavItem>
)
}
export default PermissionNavItem
Best Practice Note:
This is the same approach we use in CoreUI internal templates and our React Dashboard Template to keep codebases clean.
As demonstrated in the examples above, always use React.forwardRef when extending components — this ensures compatibility with ref-based logic like tooltips, popovers, focus management, and libraries like react-hook-form.
When merging styles and classNames, always spread the consumer’s values last so they can override your defaults.
This consistency is key to maintaining a robust and predictable UI layer as your project grows from a simple prototype to a full enterprise application. To learn how to customize the theme itself rather than individual components, see how to customize CoreUI theme in React.



