Theming Vue.js with styled-components

5 min read 1451

Theming Vue.js With Styled-Components

As web development capabilities and tools evolve, web development framework styling has mirrored that evolution. Moving away from inline styles to CSS-in-JS solutions has made the development experience more consistent.

With the styled-components library, developers can utilize CSS within JavaScript or JavaScript frameworks instead of creating traditional separate CSS files when styling. It has seen huge success in React, and now it is available for Vue projects.

In this post, we’ll see why utilizing styled-components is advantageous when styling in Vue.

Advantages of styled-components in Vue.js

Build your own components

Styled-components gives you the freedom to make your own custom styled components in Vue. You can style the HTML tags and give them the name of your choice to make your code more readable.

No classes policy

With styled-components, everything is done with the help of props. You can dynamically change the style of your components without using classes. It gives you the power to use the ternary operators inside the string literals of the styled components.

Concurrent design

Styled-components makes the styling and design of your components concurrent and similar throughout the entire application without much effort. The theming capabilities provide a central place to define the basic design elements such as color, size, and spacing, and can be easily integrated into all of the components in the app.

A huge community

Seeing tremendous growth, the styled-components community provides help for any issue and has a popular library for developers.

Now that we’ve seen the benefits of the styled-components, it’s time to install the library in our Vue project and look at how we can use its different features.

Installing styled-components in Vue.js

Before installing the library, have a Vue project up and running on your local machine. With a project set up, install the library with the following command:

npm i vue-styled-components

If you used Vue CLI to set up the project, the folder structure will look something like this:

We made a custom demo for .
No really. Click here to check it out.

Vue CLI Project Folder

With all the styles removed from our Vue app, HelloWorld.vue looks like the following:

// HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

Let’s run the project to see the following output in the browser:

Vue App Output In Browser

As we can see, there is a simple h1 header tag with no styles applied. We will style this h1 with styled-components, and we must create a new folder in the src directory to store them. In that folder, create a Header.js file. The project structure will look as follows:

H1 Styled-Components Folder

Then, add the following lines of code in Header.js:

import styled from "vue-styled-components";

export const StyledHeader = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: red;
  background-color: grey;
`;

Finally, we can register StyledHeader in HelloWorld.vue and use it instead of h1:

<template>
  <div class="hello">
    <StyledHeader>{{ msg }}</StyledHeader>
  </div>
</template>

<script>
import {StyledHeader} from "../styled-components/Header"
export default {
  name: 'HelloWorld',
  components:{
    StyledHeader
  },
  props: {
    msg: String
  }
}
</script>

Now, let’s start the server and see how the plain and boring header tag changes:

The Header Tag Changes

As we can see, the required styles have been applied without using any CSS!

Passing the props in styled-components

Styled components, like any other components, have the ability to accept props. For example, we can create an input field and pass a prop to it. Here, we’ll create a new component named Input.js in the components folder and add the following code to it:

import styled from "vue-styled-components";

export const StyledInput = styled.input`
  font-size: 1.25em;
  padding: 0.5em;
  margin: 0.5em;
  color: blueviolet;
  border: none;
  background-color: lavender;
  border-radius: 3px;

  &:hover {
    box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.1);
  }
`;

The next step is to use it in HelloWorld.vue:

<template>
  <div class="hello">
    <StyledHeader>{{ msg }}</StyledHeader>
    <StyledInput/>  
  </div>
</template>

<script>
import {StyledInput} from "../styled-components/Input"
import {StyledHeader} from "../styled-components/Header"

export default {
  name: 'HelloWorld',
  components:{
    StyledInput,StyledHeader
  },
     props: {
    msg: String
  }

}
</script>

Saving the changes will reflect them in the browser, confirming our input is rendered:

Render The Input Field In The Browser

But this looks weird without a proper input. Let’s pass it as a prop to StyledInput along with the type:

<template>
  <div class="hello">
  <StyledHeader>{{ msg }}</StyledHeader>
  <StyledInput placeholder="Password" type="text"/>  
  </div>
</template>

...

Running this gives us the following output:

Styled Input Appears In Browser

Dynamic styling with props in Vue.js

This is one of the strongest features of styled-components. It allows developers to set dynamic styles without using tons of classes.

Because styled-components can take props and apply style based on props, let’s give custom props to StyledHeader.

Let’s modify our Header.js file as follows:

import styled from "vue-styled-components";
const hdrProps = { primary: Boolean };

export const StyledHeader = styled("h1", hdrProps)`
  font-size: 1.5em;
  text-align: start;
  color: ${(props) => (props.primary ? "white" : "red")};
  background-color: ${(props) => (props.primary ? "green" : "yellow")};
`;

Here, we have defined the props for our StyledHeader. The styled function takes the HTML element with the props as an argument, after which we can specify the behavior of our CSS based on the value of that prop.

Let’s run the project without giving any prop to our previously created header, and see the following output in the browser:

 

This is working exactly as we have specified. Now, let’s provide a primary prop to our StyledHeader, and check whether the styles are applied correctly:

<template>
  <div class="hello">
  <StyledHeader primary>{{ msg }}</StyledHeader>
  <StyledInput placeholder="Password" type="text"/>  
  </div>
</template>

<script>
import {StyledInput} from "../styled-components/Input"
import {StyledHeader} from "../styled-components/Header"

export default {
  name: 'HelloWorld',
  components:{
    StyledInput,StyledHeader
  },
     props: {
    msg: String
  }

}
</script>

As we can see, the StyledHeader is accepting primary as a prop. After saving the changes, our project renders the following output:

StyledHeader Accepting The Primary Output In The Browser

With this, we have successfully changed the style based on our props, giving us the basic concept behind the approach. Styles with props can be changed with button events, form submissions, and more. We can now leverage the full power of dynamic styling with styled-components.

Applying the same style to multiple components

Styled-components also provides the ability to make components follow the same style. This creates a consistent style for applications and removes a lot of repetitious code.

By simply adding the following line of code in Header.js, we can apply the following to use the same styles for h2:

export const StyledHeader2
= StyledHeader.withComponent("h2");

After using this component in the HelloWorld.vue file, we will get the following output:

Applying The Same Styles To H2

Dynamically changing the type of rendered component

Sometimes, components must change based on a specific scenario but retain the same styles. For this instance, styled-components can use a prop to change the component being rendered.

If we apply the as prop to change the StyledHeader, we can change it to a button:

<template>
  <div class="hello">
  <StyledHeader as=button>{{ msg }}</StyledHeader>
  <StyledInput placeholder="Password" type="text"/>  
  </div>
</template>

The browser then gives us the following output:

Change The StyledHeader Button

Inspecting the role, we can clearly see that it is a button:

The Role is a Button

Extending styles

If changes must be made to the component styling without rewriting it, we can override or add new styles to it.

By creating a new component named NewHeader.js, we can override the color attribute from the previously created Header.js.

Then, let’s add the following code in the NewHeader.js:

import { StyledHeader } from "./Header";
export const NewHeader = StyledHeader.extend`
  color: purple;
  border-color: purple;
`;

Let us now render and use it in our HelloWorld.vue file:

<template>
  <div class="hello">
  <StyledHeader >{{ msg }}</StyledHeader>
  <NewHeader >{{ msg }}</NewHeader>
  <StyledInput placeholder="Password" type="text"/>  
  </div>
</template>

<script>
import {StyledInput} from "../styled-components/Input"
import {NewHeader} from "../styled-components/NewHeader"

import {StyledHeader} from "../styled-components/Header"

export default {
  name: 'HelloWorld',
  components:{
    StyledInput,StyledHeader,NewHeader
  },
     props: {
    msg: String
  }

}
</script>

After saving the changes, we get the following output:

Override The Color Attribute

As we can see, we have overridden the color of Header.js and used its styling in our newly created NewHeader.js.

Conclusion

Styled-components is a powerful library that solves most of the pain points we would find using plain CSS. While the learning curve can be steep initially, the benefits are worth it.

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

One Reply to “Theming Vue.js with styled-components”

  1. I don’t understand why I would need styled components in vue. It already has excellent support for css and sass. And if you need dynamic css you can always use a method or computed that returns an object and bind it to the style

Leave a Reply