Week 6 - Joy UI and Styling
There are 3 primary ways to customize JoyUI component styles.
- The SX Prop
- Custom Components
- Theming
- Modifying theme colors and attributes
- Component Customization
The SX Prop
The SX Prop is the primary way to apply styles on an individual component. While you can apply style
or className
to JoyUI components, using the SX prop has a few advantages:
- Theme aware - the SX property is theme aware
- We can use something like
primary.main
to use our primary theme color
- We can use something like
- React/JS friendly syntax
- ex,
backgroundColor
vs `background-color
- ex,
- Special utilities
- Spacing Utilities - This is by far the most helpful
m: 1
- apply margin to all sides of a “standard value” of 1mx: 2
- apply left and right margins of a “standard value” of 2py: 2
- apply top and bottom padding of a “standard value” of 2
- Typography - utilize standard fonts and font-weights by name
fontWeight: light
might mean a weight of 400 or 500, depending on font configuration
- Responsive Design: Setting different CSS styles based on the size of the screen
- Example: Display items in a column on screens up to a “large” size, then display as a row
{display: 'flex', flexDirection: {xs: 'column', lg: 'row'}}
- Spacing Utilities - This is by far the most helpful
<Input sx={{display: 'flex', flexDirection: 'column'}} />
When specifying the SX prop:
- We need a double set of curly braces
{{ /* */ }}
.- The first set says “open the Javascript context”
- The second set says “create a new object”
- We cannot use any keys with a
-
in them, as that is invalid JS- Ex,
background-color
is invalid - we’d need to usebackgroundColor
instead
- Ex,
What we’re really doing here is passing a JS object to the SX prop:
const style = {
display: 'flex',
flexDirection: 'column'
}
return <Input sx={style} />
Conditional Style Overrides with Arrays
By passing an Array to the SX prop, you can override certain values with conditions. The last item passed to the array will take precedence
<Box
sx={[
// note we're passing an array of objects, instead of an object
{
'&:hover': {
color: 'red',
backgroundColor: 'white',
},
},
// apply this if foo is true
foo && {
'&:hover': { backgroundColor: 'grey' },
},
// apply this if bar is true
// if both foo and bar are true,
// 'yellow' take precendence as it's last
bar && {
'&:hover': { backgroundColor: 'yellow' },
},
]}
/>
Spacing - Padding and Margin
Remember, padding includes the background, margin does not
https://lab.ci256.cloud/week6?id=spacing-margin-padding
Custom Components
Whenever you have a component in the UI that is used multiple times, we typically want to make a custom component from it. We’ve already created components in this class, but usually for a single use.
For example, we might want to create an input field that handles displaying errors to the user.
type Props = {
value?: string // initial value
onChange?: (value: string) => void; // on change callback
error?: string; // error message to display
}
export function InputField({value, onChange, error}) {
const [val, setValue] = useState(value);
useEffect(() => {
onChange?.(val)
}, [val])
return <Box sx={{display: 'flex-col'}}>
<Input
value={val}
color={error ? 'danger' : 'primary'}
onChange={(e) => setValue(e.target.value)}
sx={{mb: 1}}
/>
{error && <Alert color='danger'>{error}</Alert>}
</Box>
}
// usage
<InputField />
<InputField error='Invalid Password: too short' />
We’ve defined a couple of style/display attributes here:
- Display Input and Alert on top of one-another using flex-col layout
- Create margin between the Input and the item below it
- Only display an “Alert” colored “Danger” when error is present
Now, we won’t need to repeat ourselves if we want another input box with an alert below it. We can simply re-use the newly defined InputField
component in multiple places.
This is a major concept of modern web development - think of components as re-usable functions. We want to be DRY programmers - “Don’t Repeat Yourself”
JoyUI Theme Customization
You can read more about themes here: https://mui.com/joy-ui/customization/approaches/#theming
Theming will be not be required for this class, but you are welcome to play around with it if you’d like.