Vue JS applying parent stylesheet to imported component - javascript

I'm just getting started with Vue JS and I'm performing a pretty basic component import like this:
<script>
import footer from '#/templates/footer.vue'
export default {
components: {
footer
}
}
</script>
<style>
#import '#/css/style.css';
</style>
The problem is that the styles from style.css isn't being applied to the elements inside footer.vue. How can I apply the styles from style.css to elements inside footer.vue?
Thanks!
Update
The footer component just looks like this:
<template >
<view id="footer_outer_container">
...
</view>
</template>
<script>
export default {
name: "footer",
props: {},
methods: {}
}
</script>
<style>
</style>
And the CSS is just a regular style.css file some classes and styles.

Related

Style Mui child component within parent component using CSS modules

I am following these docs in order to style a material ui component (Paper) within a component (Menu) I am using.
I am using CSS modules to style my components (with Webpack as a bundler) :
// menu.js
import React from 'react';
import { StyledEngineProvider } from '#mui/material/styles';
...
import styles from './styles.module.css';
import Menu from '#mui/material/Menu';
import MenuItem from '#mui/material/MenuItem';
const MyMenu = (props) => {
...
return (
<StyledEngineProvider injectFirst>
<div id="my-menu">
<Button id="button-react-component" onClick={handleClick}>
My Menu
</Button>
<Menu
id="menu-react-component"
...
className={styles.menu}
>
<MenuItem ...>
<span> Example 1 <span>
</MenuItem>
</Menu>
</div>
);
}
// styles.module.css
.menu {
color: white;
}
.menu .MuiPaper-root {
background-color: red
}
// Also tried :
.menu .root {
background-color: red
}
My goal is to have the MuiPaper component have a given background-color. MuiPaper is a component that comes from the Menu component, but I am not using MuiPaper directly as I am only declaring the parent (<Menu>).
Ideally I want to use .css files for styling. I use webpack to bundle my css files into modules.
Here's what I see in my browser :
Notice how the background-color "red" is not applied on that last screenshot.
Thanks :)
CSS modules can't override a style from another CSS module (or elsewhere). There's a few ways to get around this:
Add another class specifically for the .menu paper, e.g. .menuPaper, and add it via PaperProps on the Menu component:
.menuPaper {
background-color: blue;
}
<Menu
id="menu-react-component"
...
className={styles.menu}
PaperProps={{ className: styles.menuPaper }}
>
Add the :global selector to your css selector:
.menu :global .MuiPaper-root {
background-color: red;
}
CSS modules work by "modulifying" CSS classnames by adding a unique ID to the end of them. The :global selector can be used to disable this and preserve the classname instead.
The difference between these two methods is that if you had multiple Menu components in your MyMenu component, using the :global method would give all the Menu instances inside of MyMenu the same background. With the PaperProps method only specific Menus with PaperProps={{ className: styles.menuPaper }} would get the styles applied.
css-loaderdocs: https://github.com/webpack-contrib/css-loader#scope
MUI Menu docs: https://mui.com/api/menu/#props (also see Popover component)

How to toggle sidebar without page reload when router-link is clicked in Vue 3

I have a sidebar component that works similar to a modal. When a button is clicked, the sidebar translates into the viewport with nav links. These nav links are actually router-links that are wired up to a vue-router.
What I'm trying to accomplish
When I click on a router-link that is inside my sidebar component, I want the sidebar to transition off the viewport and I want the clicked router-link's component to render without the page reloading.
What's currently happening
When I click on the router-link, the sidebar is removed instantly from the DOM. It does not translate off the screen as intended. Also, the page is reloaded.
What else have I tried
I also tried moving the <transition> wrapper inside TheSidebar.vue component along with the associated CSS classes, and I passed sidebarIsVisible as a prop from App.vue to TheSidebar.vue.
My code
A Codesandbox demo can be found here
App.vue
<template>
<router-view></router-view>
<button #click="toggleSidebar" class="toggleBtn">Toggle Sidebar</button>
<transition name="sidebar">
<the-sidebar
v-if="sidebarIsVisible"
#link-clicked="toggleSidebar"
></the-sidebar>
</transition>
</template>
<script>
import TheSidebar from "./components/TheSidebar.vue";
export default {
components: {
TheSidebar,
},
data() {
return {
sidebarIsVisible: false,
};
},
methods: {
toggleSidebar() {
this.sidebarIsVisible = !this.sidebarIsVisible;
},
closeSidebar() {
this.sidebarIsVisible = false;
},
},
};
</script>
<style>
/* basic styling */
.toggleBtn {
position: fixed;
top: 5px;
left: 5px;
}
.sidebar-enter-active {
animation: slide-sidebar 0.3s ease;
}
.sidebar-leave-active {
animation: slide-sidebar 0.3s ease reverse;
}
#keyframes slide-sidebar {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
</style>
TheSidebar.vue
<template>
<div class="sidebar">
<nav>
<ul>
<li>
<router-link #click="$emit('link-clicked')" to="/link1">
Link 1
</router-link>
</li>
<li>
<router-link #click="$emit('link-clicked')" to="/link2">
Link 2
</router-link>
</li>
</ul>
</nav>
</div>
</template>
<script>
export default {
emits: ["link-clicked"],
};
</script>
<style scoped>
/* basic styling */
</style>
main.js
import { createApp } from "vue";
import { createRouter, createWebHistory } from "vue-router";
import App from "./App.vue";
import LinkOne from "./components/LinkOne.vue";
import LinkTwo from "./components/LinkTwo.vue";
const app = createApp(App);
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: "/link1", component: LinkOne },
{ path: "/link2", component: LinkTwo }
]
});
app.use(router);
app.mount("#app");
There are a couple of things I'm unsure about here but I'll try and explain what I think is happening.
Firstly, the click event on the router-link is what's causing the page to reload, but I can't find anything in the docs mentioning this as expected behaviour (it might be worth opening an issue on the GitHub repo).
The fix for this is to use event-delegation by moving the event-handler onto the ul and creating a method to determine if a link has been clicked (example below).
Secondly, and this is where things get weird, in VSCode, using kebab-case in the child components' emitted event seems to prevent anything from being emitted, so changing them to camelCase fixes this. But, trying this in CodeSandbox simply doesn't work, and ESLint complains that the emitted event should be kebab-case. So, in CodeSandbox, the opposite is true: the emitted event names should be kebab-case and the listener should be camelCase! Absolutely no idea why as this goes against what the docs say on casing:
...we recommend using kebab-cased event listeners when you are using in-DOM templates.
Again, I can't find anything in the docs explicitly saying you need to use camelCase when emitting an event, it just says kebab-case is preferred when listening for an event.
So, all in all, for your code to work in VSCode and in a way which follows what is recommended by the docs, you need to change it to this:
<template>
<div class="sidebar">
<nav>
<!-- Move event here -->
<ul #click="handleClick($event)">
<li>
<router-link to="/link1">
Link 1
</router-link>
</li>
<li>
<router-link to="/link2">
Link 2
</router-link>
</li>
</ul>
</nav>
</div>
</template>
<script>
export default {
emits: ['linkClicked'], // Use camelCase for emitting
methods: {
handleClick(e) {
// Check the target is a link being clicked
if (e.target.localName !== 'a') return
this.$emit('linkClicked')
}
}
}
</script>
Keep App.vue exactly as you have it already and it should work.
For your code to work in CodeSandbox, swap the casing:
...
emits: ['link-clicked'], // Use kebab-case for emitting
...
this.$emit('link-clicked')
...
App.vue:
#linkClicked="toggleSidebar"
Working example.
If anyone could shed some light on this, it'd be great as I'm completely stumped on what's happening here.

How to pass styles to child component and use it as scoped style in Vue?

I have a parent component:
<template>
<ChildComponent :styles="styles" />
</template>
<script>
export default {
data: () => ({
styles: `
p {
color: red
}
`
})
}
</script>
And this is the child component:
<template>
<p>Hello World</p>
</template>
<script>
export default {
props: {
styles: {
type: String,
required: true
}
}
}
</script>
<style scoped>
</style>
Now I want to use those styles provided by the parent component in child as scoped styles. Like for example:
<!-- ChildComponent.vue -->
<style scoped>
p {
color: red
}
</style>
Is there any way to do so?
If you want to target the child elements with scoped styling you have to use the deep selector.
Which can be done with
a >>> b { color : red; }
/deep/ a b { color : red; }
a::v-deep b { color : red; }
Here is the full explanation: https://vue-loader.vuejs.org/guide/scoped-css.html#child-component-root-elements
If you wanna add the style in your child component, based on the parent component which is calling it, you can pass an attribute as a prop and use it as a class into the child component. Following your example:
Parent component:
<template>
<ChildComponent styles="parent-style" />
</template>
Child component:
<template>
<section :class="styles">
<p>Hello World</p>
</section>
</template>
<script>
export default {
props: {
styles: {
type: String,
required: true
}
}
}
</script>
<style lang="scss" scoped>
.parent-style {
p {
color: red;
}
}
</style>
Please note that it does not answer scoped CSS.
I am using CSS modules, still might help or just to improve following approach.
Send class names to child component from parent, such as:
Parent Template
<template>
<header :class="$style.Header">
<!-- send class names to **Child-Component** using `v-bind` through the className attribute -->
<HeaderLogo :className="$style.Header__logo" />
</header>
</template>
Child-Template
<template>
<div :class="className">Blah</div>
</template>
CSS Module
<style lang="scss" module>
.Header {
white-space: nowrap;
&__logo {
width: 100%;
}
}
</style>

Styled-components doesn't output style tag

I've set up a new project in React using Webpack, and wanted to give a try to Styled Components.
My index.js looks like this:
import React from "react"
import ReactDOM from "react-dom"
import Page from "./site/Page"
import styled from 'styled-components'
// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
// Create a Wrapper component that'll render a <section> tag with some styles
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
const Index = props => {
return (
<Page>
<Wrapper>
<Title>Test</Title>
</Wrapper>
</Page>);
};
ReactDOM.render(<Index/>, document.getElementById("app"))
The code outputted by styled-components on the HTML page looks fine but the <style> the on the head doesn't get added, resulting in no css style at all.
<section class="sc-bwzfXH gzMTbA">
<h1 class="sc-bdVaJa bzmvhR">Test</h1>
</section>
Does somebody have any suggestions?
Take a look at this API: CSSStyleSheet.insertRule().
Styled Components inserts empty style tags for hosting these dynamically injected styles.

CSS doesn't apply to a component

I have a react component that is wrapped up in div:
AccountLogin.jsx:
import './AccountLogin.css';
export default observer(() => (
<div className="content">
Something here
</div>
));
AccountLogin.css:
.content {
color: blue;
background-color: blue;
margin: 500px;
}
But the css doesn't apply to my rendered component AccountLogin.
Any ideas why that could happen?
Looking at rfx-stack source, I can see that files suffixed with .global.css are imported in global scope where as others are imported as css-modules.
So you can either rename your file to AccountLogin.global.css or use the imported class name:
import styles from './AccountLogin.css';
Within component:
<div className={styles.content}>...</div>

Categories