Skip to main content

Inline Styles in React (Part 2): Dynamic Styling #26

📖 Introduction

In the previous article, we learned the fundamentals of the style prop and how to apply basic inline styles. Now, it's time to unlock the true power of this technique: creating dynamic styles that change based on your component's props and state.

This is where inline styling truly shines in React. By treating styles as JavaScript objects, we can use logic to modify them on the fly, creating interactive and responsive user interfaces without writing dozens of CSS classes.


📚 Prerequisites

Before we begin, please ensure you have a solid grasp of the following concepts:

  • React Inline Styles: You must be comfortable with the style prop and the "double-curly" syntax {...}.
  • React Props and State: You should understand how to pass props to a component and manage basic state with the useState hook.
  • JavaScript Conditionals: Familiarity with if statements and the ternary operator (condition ? valueIfTrue : valueIfFalse).

🎯 Article Outline: What You'll Master

In this article, you will learn:

  • Styling with Props: How to change a component's appearance based on the props it receives.
  • Styling with State: How to make a component's style react to user interactions by linking it to state.
  • Combining Styles: How to merge a base style object with dynamic styles using the JavaScript spread syntax.
  • Practical Example: Building an interactive component whose style changes when you click it.

🧠 Section 1: The Core Concept: Styles are Just Data

The key to dynamic styling is to remember that an inline style in React is just a JavaScript object. And just like any other data in your component, you can build this object using variables, logic, and calculations.

Instead of thinking of styles as static rules in a .css file, think of them as another piece of data, like userName or itemCount, that can be constructed and changed in response to events.

This allows for powerful patterns:

  • A ProgressBar component can set its width style based on a percentComplete prop.
  • A Button component can change its backgroundColor based on an isActive state variable.
  • An Avatar component can set its borderColor based on an isOnline prop.

💻 Section 2: Dynamic Styles Based on Props

Let's start by creating a component whose style is determined by the props passed to it. We'll create a Badge component that can have different colors.

// code-block-1.jsx
import React from 'react';

function Badge({ color, children }) {
const badgeStyle = {
padding: '8px 12px',
borderRadius: '16px',
color: 'white',
fontWeight: 'bold',
// Dynamically set the background color based on the 'color' prop
backgroundColor: color || 'gray', // Default to gray if no color is provided
};

return (
<span style={badgeStyle}>
{children}
</span>
);
}

// How to use it:
function App() {
return (
<div>
<Badge color="blue">Info</Badge>
<Badge color="green">Success</Badge>
<Badge color="red">Error</Badge>
</div>
);
}

export default App;

Code Breakdown:

  1. function Badge({ color, children }): Our component accepts a color prop.
  2. backgroundColor: color || 'gray': Inside our badgeStyle object, we use a JavaScript logical OR (||) expression. If the color prop is provided, it will be used. If it's undefined or null, it will fall back to 'gray'.
  3. <span style={badgeStyle}>: We apply the dynamically constructed style object to our element.

This pattern makes the Badge component highly reusable and configurable directly from where it's used.


🛠️ Section 3: Dynamic Styles Based on State

The most powerful use case for inline styles is making them change in response to user actions. This is done by linking styles to a component's state.

Let's build a simple "like" button that changes color when clicked.

// code-block-2.jsx
import React, { useState } from 'react';

function LikeButton() {
// 1. Set up a state variable to track if the button is liked
const [isLiked, setIsLiked] = useState(false);

// 2. Define the base style for the button
const buttonStyle = {
padding: '10px 20px',
border: 'none',
borderRadius: '5px',
cursor: 'pointer',
transition: 'all 0.3s ease', // Add a smooth transition effect
};

// 3. Define the dynamic style based on the 'isLiked' state
const dynamicStyle = {
backgroundColor: isLiked ? 'deeppink' : 'lightgray',
color: isLiked ? 'white' : 'black',
};

// 4. Handle the click event to toggle the state
const handleClick = () => {
setIsLiked(!isLiked);
};

return (
<button
// 5. Merge the base and dynamic styles together
style={{ ...buttonStyle, ...dynamicStyle }}
onClick={handleClick}
>
{isLiked ? '♥ Liked' : '♡ Like'}
</button>
);
}

export default LikeButton;

Step-by-Step Walkthrough:

  1. useState: We initialize an isLiked state variable to false.
  2. Base Styles: We create a buttonStyle object with styles that will always apply, regardless of state.
  3. Dynamic Styles: We create a dynamicStyle object. Here, we use a ternary operator to check the value of isLiked. If it's true, the background is pink; otherwise, it's gray.
  4. Event Handler: The handleClick function simply toggles the isLiked state from true to false and vice-versa.
  5. Merging Styles: In the style prop, we use the JavaScript spread syntax (...) to merge our two style objects: style={{ ...buttonStyle, ...dynamicStyle }}. This creates a new object containing all properties from both. If there are any overlapping properties (like backgroundColor), the property from the last object in the sequence (dynamicStyle) will win.

When you click the button, handleClick is called, isLiked changes, the component re-renders, dynamicStyle is recalculated with new values, and the button's appearance updates instantly.


✨ Section 4: Best Practices

  • Separate Static and Dynamic Styles: As shown in the LikeButton example, it's a great practice to separate your static base styles from the styles that change. This makes your code cleaner and easier to reason about.
  • Use Ternary Operators for Simple Logic: The ternary operator (condition ? A : B) is perfect for simple conditional styles.
  • Extract Complex Logic: If your style logic becomes complex (e.g., multiple if/else checks), extract it into a helper function outside of your return statement to keep your JSX clean.
  • Combine with className: Don't forget that you can use both className and style on the same element. Use className for the majority of static styles and reserve the style prop for the few properties that truly need to be dynamic.

💡 Conclusion & Key Takeaways

You've now unlocked the primary superpower of inline styles in React: the ability to create components that visually respond to application data and user interactions in real-time.

Let's summarize the key takeaways:

  • Styles are Data: Treat your style objects as another piece of data in your component that can be built dynamically.
  • Props for Configuration: Use props to pass in values that control a component's appearance from its parent.
  • State for Interaction: Use state to change a component's style in response to events like clicks or hovers.
  • Merge with Spread Syntax: The ... spread syntax is the standard way to combine a base style object with a dynamic style object.

Challenge Yourself: Create a CharacterCounter component that has a text input. As the user types, display a character count below the input. The character count's color should be black by default, but should turn red if the character count exceeds a maxLength prop that you pass to the component.


➡️ Next Steps

With a solid understanding of both external CSS and dynamic inline styles, you are well-equipped to handle most styling scenarios. In our next article, we will begin to explore a hybrid approach that offers the best of both worlds: "CSS Modules (Part 1): How CSS Modules work and how to set them up."

Thank you for your dedication. Stay curious, and happy coding!


glossary

  • Dynamic Style: A style whose value is determined by a variable, such as a component's props or state, allowing it to change during runtime.
  • Ternary Operator: A conditional operator in JavaScript with the syntax condition ? exprIfTrue : exprIfFalse. It's a concise alternative to an if...else statement.
  • Spread Syntax (...): A JavaScript operator that allows an iterable (like an array) or an object to be expanded in places where zero or more arguments or elements/properties are expected.

Further Reading