Overview
While Natura Design System provides ready-to-use themes for each brand, you may need to customize certain aspects for your specific use case. This guide covers the available customization options.
Important: Do not try to override theme palette or other core tokens. The Design System themes are designed to maintain consistency across all brands. Only customize when absolutely necessary.
Typography Customization
The buildTheme utility in @naturacosmeticos/natds-web supports typography customization:
Basic Typography Override
import { buildTheme } from '@naturacosmeticos/natds-web'
// Apply typography customization
const theme = buildTheme ( 'natura' , 'light' , 'typography' )
This option automatically applies:
fontFamily from the theme’s body typography
fontWeightRegular from the theme’s body typography
Implementation
export type ThemeMode = 'light' | 'dark'
export type Brand = ThemeBrandName
export type CustomOption = 'typography'
export const buildTheme = ( brand : Brand , mode : ThemeMode , customOption ?: CustomOption ) => {
const theme = themes [ brand ][ mode ]
if ( customOption === 'typography' ) {
return {
... theme ,
typography: {
... theme . typography ,
fontFamily: theme . typography . body ?. regular . fontFamily ,
fontWeightRegular: theme . typography . body ?. regular . fontWeight
}
}
}
return theme
}
Deep Customization
For advanced use cases, you can extend the theme object after building it:
Extending Theme Properties
import { buildTheme } from '@naturacosmeticos/natds-react'
import { Theme } from '@naturacosmeticos/natds-themes'
const baseTheme = buildTheme ( 'natura' , 'light' )
const customTheme : Theme = {
... baseTheme ,
// Add custom properties specific to your app
// Note: This should be used sparingly
spacing : ( factor : number ) => ` ${ 8 * factor } px`
}
Extending core theme properties can break design system consistency. Use this approach only when you cannot achieve your goals through the standard API.
Theme Context in Components
Access the current theme in your components using react-jss:
Using withStyles
import React from 'react'
import { withStyles , WithStyles } from 'react-jss'
import { Theme } from '@naturacosmeticos/natds-themes'
const styles = ( theme : Theme ) => ({
root: {
backgroundColor: theme . color . primary ,
color: theme . color . onPrimary ,
padding: theme . spacing ( 2 ),
borderRadius: theme . shape . borderRadius . medium
},
title: {
... theme . typography . h1 ,
marginBottom: theme . spacing ( 2 )
}
})
interface Props extends WithStyles < typeof styles > {
title : string
children : React . ReactNode
}
const CustomCard : React . FC < Props > = ({ classes , title , children }) => (
< div className = { classes . root } >
< h1 className = { classes . title } > { title } </ h1 >
{ children }
</ div >
)
export default withStyles ( styles )( CustomCard )
Using useTheme Hook
import React from 'react'
import { useTheme } from 'react-jss'
import { Theme } from '@naturacosmeticos/natds-themes'
const CustomComponent : React . FC = () => {
const theme = useTheme < Theme >()
return (
< div
style = { {
backgroundColor: theme . color . surface ,
color: theme . color . onSurface ,
padding: theme . spacing ( 3 ),
borderRadius: theme . shape . borderRadius . large
} }
>
< h2 style = { theme . typography . h2 } >
Accessing Theme Values
</ h2 >
< p style = { theme . typography . body1 } >
You can access any theme token through the useTheme hook.
</ p >
</ div >
)
}
export default CustomComponent
Available Theme Tokens
Color Tokens
theme . color . primary
theme . color . secondary
theme . color . surface
theme . color . background
theme . color . error
theme . color . warning
theme . color . success
theme . color . info
theme . color . onPrimary
theme . color . onSecondary
theme . color . onSurface
theme . color . onBackground
// ... and many more
Typography Tokens
theme . typography . h1
theme . typography . h2
theme . typography . h3
theme . typography . h4
theme . typography . h5
theme . typography . h6
theme . typography . body1
theme . typography . body2
theme . typography . subtitle1
theme . typography . subtitle2
theme . typography . button
theme . typography . caption
theme . typography . overline
Spacing
theme . spacing ( 1 ) // Base spacing unit
theme . spacing ( 2 ) // 2x spacing
theme . spacing ( 3 ) // 3x spacing
// etc.
Border Radius
theme . shape . borderRadius . none // 0
theme . shape . borderRadius . small // 2px
theme . shape . borderRadius . medium // 4px
theme . shape . borderRadius . large // 8px
theme . shape . borderRadius . circle // 999px
Shadows
theme . shadows [ 0 ] // No shadow
theme . shadows [ 1 ] // Subtle shadow
theme . shadows [ 2 ] // Small shadow
theme . shadows [ 4 ] // Medium shadow
theme . shadows [ 8 ] // Large shadow
theme . shadows [ 16 ] // Extra large shadow
Icon & Avatar Sizes
theme . iconSizes . tiny
theme . iconSizes . small
theme . iconSizes . medium
theme . iconSizes . large
theme . avatarSizes . tiny
theme . avatarSizes . small
theme . avatarSizes . medium
theme . avatarSizes . large
Opacity
theme . opacity . transparent
theme . opacity . lower
theme . opacity . low
theme . opacity . medium
theme . opacity . high
theme . opacity . opaque
Responsive Design
The theme includes Material-UI breakpoints for responsive design:
import { useTheme } from 'react-jss'
import { useMediaQuery } from '@material-ui/core'
import { Theme } from '@naturacosmeticos/natds-themes'
const ResponsiveComponent : React . FC = () => {
const theme = useTheme < Theme >()
const isMobile = useMediaQuery ( theme . breakpoints . down ( 'sm' ))
const isTablet = useMediaQuery ( theme . breakpoints . between ( 'sm' , 'md' ))
const isDesktop = useMediaQuery ( theme . breakpoints . up ( 'md' ))
return (
< div >
{ isMobile && < MobileView /> }
{ isTablet && < TabletView /> }
{ isDesktop && < DesktopView /> }
</ div >
)
}
Breakpoint values:
xs: 0px (extra-small)
sm: 600px (small)
md: 960px (medium)
lg: 1280px (large)
xl: 1920px (extra-large)
Custom Component Styling
Create custom styled components using theme tokens:
import React from 'react'
import { createUseStyles } from 'react-jss'
import { Theme } from '@naturacosmeticos/natds-themes'
const useStyles = createUseStyles (( theme : Theme ) => ({
card: {
backgroundColor: theme . color . surface ,
borderRadius: theme . shape . borderRadius . medium ,
boxShadow: theme . shadows [ 2 ],
padding: theme . spacing ( 3 ),
marginBottom: theme . spacing ( 2 ),
transition: 'box-shadow 0.3s ease' ,
'&:hover' : {
boxShadow: theme . shadows [ 8 ]
}
},
header: {
... theme . typography . h3 ,
color: theme . color . primary ,
marginBottom: theme . spacing ( 2 )
},
content: {
... theme . typography . body1 ,
color: theme . color . onSurface ,
lineHeight: 1.6
},
footer: {
marginTop: theme . spacing ( 2 ),
paddingTop: theme . spacing ( 2 ),
borderTop: `1px solid ${ theme . color . divider } `
}
}))
interface CardProps {
title : string
content : string
footer ?: React . ReactNode
}
const StyledCard : React . FC < CardProps > = ({ title , content , footer }) => {
const classes = useStyles ()
return (
< div className = { classes . card } >
< h3 className = { classes . header } > { title } </ h3 >
< p className = { classes . content } > { content } </ p >
{ footer && < div className = { classes . footer } > { footer } </ div > }
</ div >
)
}
export default StyledCard
Dynamic Theming
Switch themes dynamically based on user preferences or application state:
import React , { useState , useEffect } from 'react'
import { ThemeProvider , buildTheme } from '@naturacosmeticos/natds-react'
import type { Brand , ThemeMode } from '@naturacosmeticos/natds-react'
const App : React . FC = () => {
const [ brand , setBrand ] = useState < Brand >( 'natura' )
const [ mode , setMode ] = useState < ThemeMode >( 'light' )
// Persist theme preferences
useEffect (() => {
const savedBrand = localStorage . getItem ( 'theme-brand' ) as Brand
const savedMode = localStorage . getItem ( 'theme-mode' ) as ThemeMode
if ( savedBrand ) setBrand ( savedBrand )
if ( savedMode ) setMode ( savedMode )
}, [])
useEffect (() => {
localStorage . setItem ( 'theme-brand' , brand )
localStorage . setItem ( 'theme-mode' , mode )
}, [ brand , mode ])
// Detect system dark mode preference
useEffect (() => {
const mediaQuery = window . matchMedia ( '(prefers-color-scheme: dark)' )
const handleChange = ( e : MediaQueryListEvent ) => {
setMode ( e . matches ? 'dark' : 'light' )
}
mediaQuery . addEventListener ( 'change' , handleChange )
return () => mediaQuery . removeEventListener ( 'change' , handleChange )
}, [])
const theme = buildTheme ( brand , mode )
return (
< ThemeProvider theme = { theme } cssPrefix = "app" >
< YourApp
onBrandChange = { setBrand }
onModeChange = { setMode }
currentBrand = { brand }
currentMode = { mode }
/>
</ ThemeProvider >
)
}
export default App
CSS Variables Approach
For better runtime performance, consider exporting theme tokens as CSS variables:
import React , { useEffect } from 'react'
import { useTheme } from 'react-jss'
import { Theme } from '@naturacosmeticos/natds-themes'
const ThemeVariablesProvider : React . FC = ({ children }) => {
const theme = useTheme < Theme >()
useEffect (() => {
const root = document . documentElement
// Set CSS variables
root . style . setProperty ( '--color-primary' , theme . color . primary )
root . style . setProperty ( '--color-secondary' , theme . color . secondary )
root . style . setProperty ( '--color-surface' , theme . color . surface )
root . style . setProperty ( '--color-background' , theme . color . background )
root . style . setProperty ( '--spacing-unit' , ` ${ theme . spacing ( 1 ) } px` )
root . style . setProperty ( '--border-radius-medium' , ` ${ theme . shape . borderRadius . medium } px` )
// ... set other variables as needed
}, [ theme ])
return <> { children } </>
}
export default ThemeVariablesProvider
Then use in CSS:
.my-component {
background-color : var ( --color-surface );
padding : calc ( var ( --spacing-unit ) * 2 );
border-radius : var ( --border-radius-medium );
}
Best Practices
Use theme tokens consistently
Always use theme tokens instead of hardcoded values to maintain consistency and enable easy theme switching.
Avoid overriding core tokens
Don’t override palette colors, typography scales, or spacing systems. These are carefully designed for brand consistency.
Leverage existing components
Before creating custom styled components, check if existing Design System components can meet your needs.
If you customize themes, test your components across all brand themes and both light/dark modes.
Document any theme customizations in your codebase to help future developers understand why they exist.
See Also