How to inherit svg's css properties using vue svg loader - vue.js

I am using vue-svg-loader to use my svg files as a component in Vue project. When I am rendering those svgs I am losing default css properties that are inside of the svg file. I can add those css properties inside of my component where I am rendering svg files, but that kind of violates the idea of reusable components since each svg file has its own property. Is there a way to inherit their css?
'''
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 612 792" style="enable-background:new 0 0 612 792;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:none;}
.st2{fill:#FFFFFF;stroke:#000000;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:10;}
.st3{font-family:'ArialMT';}
.st4{font-size:32px;}
</style>
<font horiz-adv-x="2048">
'''

Likely what is happening is that all of your SVG files use the same class names (st0, st1, etc). They are overriding each other. You'll need to:
manually rename the classes in each file, so they use different names, or
That file looks like it came from Illustrator. Assuming they all did, then load the SVGs back into Illustrator, and re-export them. This time change which method AI uses to set the element styles. I don't have AI handy right now, but there will probably be three options (I don't recall exactly what they are called):
Internal CSS - what the file above is using
Style attributes - uses the style="..." attrinbute
Attributes - uses attributes like fill="#ff0000"
If you need to style the SVGs with CSS in your page, you'll probably want to use the last option. That's because style attributes have a higher priority than CSS, so you would need to use the CSS !important flag, which is not generally recommended.

I've found that the vue-svg-loader documentation is pretty thin, mainly because all its configuration is done via the svgo library. There are some clues in this FAQ, which shows you how to customise the svgo configuration in your webpack config.
So maybe you want something like this in your vue.config.js file:
module.exports = {
chainWebpack: (config) => {
const svgRule = config.module.rule('svg');
svgRule.uses.clear();
svgRule
.use('babel-loader')
.loader('babel-loader')
.end()
.use('vue-svg-loader')
.loader('vue-svg-loader')
.options({
svgo: {
plugins: [
addClassesToSVGElement: {
classNames: ["foo", "bar"],
}
],
},
});
},
};

Related

How to build web component with styling library using vite and vue 3?

I am able to build vue web component and load it in other pages, but I can't find document how to correctly include a UI framework. It seems the web component is under shadowDOM and import css using style tag won't work.
(Add the CDN link in the template and style is applied)
Any hint on any framework, Vuetify or Ant Design or Tailwind CSS will be appreciated.
Similar question: Vuetify build as Web component style not showing
Using custom elements without Shadow DOM is trivial. Just add like the way you do traditionally. However, with Shadow DOM, things are tricky. Only inheritable CSS styles pass through the Shadow DOM. Everything else is blocked. No straight forward integration with existing design systems (Vuetify, Ant, etc.) is not directly possible if that library is only exposing global CSS.
If the design system or a component library is exposing styles i.e. css files for individual components, then you can that with some effort.
The best solution is to use constructable stylesheet. You can use a bundler like Webpack to load the stylesheet for individual component (if and only if it is provided) as a string and feed it to the stylesheet constructor method as illustrated here.
// Read SCSS file as a raw CSS text using Webpack/Rollup/Parcel
import styleText from './my-component.scss';
const sheet = new CSSStyleSheet();sheet.replaceSync(styleText);
// Use the sheet inside the web component constructor
shadowRoot.adoptedStyleSheets = [sheet];
However, Firefox and Safari are yet to implement it.
If you need a fallback, then there are ways that are not so clean. Approach is same. Import the CSS/SCSS as a string and using the template literal, add it to the element's inner style tag.
import styleText from 'ant/button.css';
class FancyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
<!-- Styles are scoped -->
<style>
${styleText}
</style>
<div>
<p>Hello World</p>
</div>
`;
}
}
customElements.define('fancy-comp', FacyComponent);
This all relies on the assumption that ant/material/veutify is exposing styles as individual files instead of one global file.
Alternately, the browsers have started supporting the link tag inside the Shadow DOM. But again it is really useful if you have styles for individual components. Read more about that here.

Headless UI component will not take style

I'm currently playing around with Headless UI and I can't seem to style any of the components.
This is the code in my tabs file
<template>
<TabGroup>
<TabList class="bg-blue-900/20 rounded-xl">
<Tab>Products Information</Tab>
<Tab>Find Offices Nearby</Tab>
<Tab>Requirements</Tab>
</TabList>
<TabPanels>
<TabPanel>Content 1</TabPanel>
<TabPanel>Content 2</TabPanel>
<TabPanel>Content 3</TabPanel>
</TabPanels>
</TabGroup>
</template>
<script>
import { TabGroup, TabList, Tab, TabPanels, TabPanel } from '#headlessui/vue'
export default {
components: {
TabGroup,
TabList,
Tab,
TabPanels,
TabPanel,
},
}
</script>
It's either of these problems
Tailwind CSS is not installed or configured properly so you cannot use Tailwind CSS classes like 'rounded-xl'.
'bg-blue-900/20' is not an inbuilt tailwind CSS class, so either customize color in tailwind or use inbuilt colours like 'bg-blue-400', 'bg-blue-500', etc
Tailwindcss v2.1 introduced JIT mode that generates styles on-demand.
You need to enable jit mode to use such classes like bg-blug-900/20.
You can see how to do that in official doc

Nuxt how to override global css for a page

I have a project with multiple layouts, I have added the CSS globally in nuxt.config.js file like this:
css: [
'#/assets/plugins/fontawesome-free/css/all.min.css',
'#/assets/plugins/ionicons/css/ionicons.min.css',
'#/assets/plugins/feather/feather.css',
'#/assets/css/style.css',
'#/assets/css/custom-style.css',
'#/assets/css/skins.css',
]
but I want for just 1 layout to remove all css imported because the file being served is a static HTML file with all the styles inline.
Is this possible in nuxt and if not, what is the best possible workaround?
You could add the css files in your layout in a normal style block and not in nuxt.config.js.
<style lang="scss">
#import ...;
</style>
Then you can use another layout without these css files.
Remove the scope from your style on the .vue file where you want to override the global style:
<style s̶c̶o̶p̶e̶d̶>
.ProseMirror p {
color: rgb(236, 10, 10);
}
</style>
I wonder too, if you would be better off creating new vue layout files in the layout folder and applying those styles to the pages you want to affect globally, instead of pulling the css through nuxt.config.js file. Then, on the specific page that you want to override the global style, just remove the scope as I mention above. Just a thought.

Using <object> to embed svg but doesn't show anything

I was trying to use to embed the svg picture but it does not show anything. I looked at some other threads and it was suggested to add type="image/svg+xml", however, it did not solve the issue. When I am trying to look at the DOM for some reason it seems to create an endless loop. I attached the picture
This is the compononent
<template>
<div class="logo">
<object type="image/svg+xml" data="logo.svg">
</object>
</div>
</template>
This is the app.vue
template>
<div id="app">
<Demo></Demo>
</div>
</template>
<script>
import Demo from './components/Demo.vue'
export default {
name: 'app',
components: {
Demo
}
}
</script>
```[![Snapshot][1]][1]
[1]: https://i.stack.imgur.com/Q6ipO.png
This happen because vue-loader doesn’t recognize paths in just any attribute. By default just recognize these ones: https://vue-loader.vuejs.org/options.html#transformasseturls
So, there are 3 possible solutions
Note: If you are not using eslint as linter you could remove eslint comments
1: Bind the route to your image
First add the next variable to your data in the component
data() {
return {
// eslint-disable-next-line global-require
mySvg: require('../assets/logo.svg'),
};
},
Next modify your template
<object type="image/svg+xml" :data="mySvg">
2: Add vue-loader rule
If you don't want to have to bind every svg image, you could add a rule to vue-loader in order to say how to handle data attribute in a object
Go to your webpack config file, if you created the project using vue-cli 3.x you have to create a vue.config.js file in the root (same level that package.json)
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap((options) => {
// eslint-disable-next-line no-param-reassign
options.transformAssetUrls = {
object: 'data',
};
return options;
});
},
};
if you want to check that the config was added, execute vue inspect > webpack.config and expect see something like this (inside webpack.config):
{
loader: 'vue-loader',
options: {
...
transformAssetUrls: {
object: 'data'
}
}
}
More info: https://cli.vuejs.org/guide/webpack.html#working-with-webpack
3: Replace default loader and use svg as vue components
Other option is use vue-svg-loader. This loader inlines the SVGs which enables you to modify them using css. Also optimize your files with SVGO
See more: https://vue-svg-loader.js.org/#vue-cli
It is worth checking that you don't have a CSS rule hiding object tags. Otherwise it seems correct. You probably need to check the path and make sure you can reach your image. I assume your filename is a dummy, but try to use an absolute path. And make sure you can hit the path and see the image in your browser.

Why doesn't the nested component render as a slottable custom element?

Are there limitations to compiling Svelte components as custom elements? For instance, are we able to nest components? And fill slots in those nested components?
I'm having trouble using a Svelte component as a custom element in my older Vue app.
I've got a Select and a Modal component in this simplified example: https://svelte.dev/repl/4d4ad853f8a14c6aa27f6baf33751eb8?version=3.6.4
I'm then compiling these with a standard-fare rollup.config.js:
export default {
input: "src/components.js",
output: [
// ...
{ file: "dist/index.min.js", format: "umd", name }
],
plugins: [
svelte({
dev: !production,
customElement: true,
// ...
}),
resolve(),
commonjs(),
!production && livereload("public"),
production && terser()
],
// ...
};
Then I go to use the custom elements. On click of the <conversational-select>, I get markup that looks like the following:
<conversational-select label="Domains" firstvaluelabel="All Domains">
<!-- shadow-root -->
<style>...</style>
<span class="select" >
<div class="select-value">Governance Board</div>
<div class="select-label" ></div>
</span>
<!-- The below div is the appropriate markup for Modal but the style isn't inlined and isn't slotted.
<!-- maybe because it didn't append as <sk-modal>? -->
<div ><slot></slot></div>
</conversational-select>
The "Modal" is sort-of rendering. But it doesn't fill the slot with span .chips. Doesn't inline the styles like the conversational-select does. Doesn't seem to attach its own event listeners. But does seem to create the fade transition thanks to Svelte's transition:fade directive.
I can reproduce this with a vanilla html file, so it's not Vue's fault.
Am I breaking some known rule with custom elements, butting up against the limitations of Svelte's custom element compilation, or just mistaken somewhere?
I was the author of the Svelte github issue that has been mentioned. I believe that I have a fix here. There were a few issues that existed:
slotted was never set
"nested" elements were not being added correctly
I expect the Svelte authors to make changes to my pull request, but if you want to use it, you can:
Clone my branch
Run npm && npm build && npm link
Go to your project and run npm link svelte