This document outlines the styling conventions used in MQTT Explorer for visual consistency and maintainable code.
Material-UI (MUI) v7 with JSS styling via withStyles HOC.
Stack:
@mui/material(v7) - Core components and theming@mui/icons-material(v7) - Icons@mui/styles(v6) - JSS styling withwithStyles@emotion/react&@emotion/styled- CSS-in-JS foundation
Location: app/src/theme.ts
Configuration:
- Light and dark modes supported
- Primary color:
#335C67(teal/blue-green) - Secondary: Material-UI
amberpalette - Base typography:
0.9rem,userSelect: 'none'
Application:
<ThemeProvider theme={theme}>
<LegacyThemeProvider theme={theme}>
<App />
</LegacyThemeProvider>
</ThemeProvider>Access theme colors:
backgroundColor: theme.palette.background.default
color: theme.palette.text.primary
borderColor: theme.palette.dividerMaterial-UI palettes:
import { blueGrey, amber, green, red, orange } from '@mui/material/colors'
backgroundColor: blueGrey[100] // Light shade
backgroundColor: blueGrey[700] // Dark shadeTheme-conditional:
const color = theme.palette.mode === 'light' ? blueGrey[300] : theme.palette.primary.mainCode editor colors: Defined in app/src/components/Sidebar/CodeBlockColors.ts
Variants:
<Typography variant="h6">Heading</Typography>
<Typography variant="body1">Body text</Typography>
<Typography variant="caption">Caption</Typography>Font sizes:
fontSize: theme.typography.pxToRem(15)Monospace: "12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace"
8px grid system:
margin: theme.spacing(1) // 8px
padding: theme.spacing(2) // 16px
marginLeft: theme.spacing(1.5) // 12px (tree indentation)Border radius:
borderRadius: theme.shape.borderRadius // 4px defaultPrimary approach - withStyles HOC:
import { withStyles } from '@mui/styles'
import { Theme } from '@mui/material/styles'
const styles = (theme: Theme) => ({
root: {
backgroundColor: theme.palette.background.default,
padding: theme.spacing(2),
},
})
export default withStyles(styles)(MyComponent)Type assertions:
display: 'block' as 'block'
whiteSpace: 'nowrap' as 'nowrap'
overflow: 'hidden' as 'hidden'Responsive:
[theme.breakpoints.up(750)]: {
display: 'block',
}sx prop (simple cases):
<Button sx={{ color: 'primary.contrastText' }}>Text</Button>CSS animations:
animation: 'updateLight 0.5s'Theme transitions:
transition: theme.transitions.create('transform', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
})Hover:
'&:hover': {
backgroundColor: theme.palette.mode === 'light'
? blueGrey[100]
: theme.palette.primary.light,
}Selection:
selected: {
backgroundColor: (theme.palette.mode === 'light'
? blueGrey[300]
: theme.palette.primary.main) + ' !important',
}Tree nodes:
node: {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}
subnodes: {
marginLeft: theme.spacing(1.5),
}Buttons:
<Button variant="contained" color="primary">Submit</Button>
<Button variant="outlined" color="primary">Cancel</Button>
<Button>Learn More</Button>Icons:
<Icon fontSize="inherit" />
<Icon style={{ fontSize: '16px' }} />DO:
✅ Use theme variables (theme.palette.*, theme.spacing(), theme.typography.*)
✅ Use withStyles HOC for component styles
✅ Use theme.palette.mode for light/dark conditional styling
✅ Import Material-UI color palettes for extended colors
✅ Keep styles co-located with components
DON'T: ❌ Hardcode colors or spacing values ❌ Create global CSS files ❌ Duplicate style definitions ❌ Use inline styles for complex patterns
Testing: Verify in both light/dark themes, check responsive behavior, ensure accessibility.
- README.md - Project overview
- BROWSER_MODE.md - Browser mode
- .github/copilot-instructions.md - Copilot instructions