Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue/no-v-text-v-html-on-component: it should not warn if a component implements default slot #2431

Open
mitar opened this issue Mar 17, 2024 · 9 comments

Comments

@mitar
Copy link

mitar commented Mar 17, 2024

What rule do you want to change?

vue/no-v-text-v-html-on-component

Does this change cause the rule to produce more or fewer warnings?

Fewer warnings (less false positives).

How will the change be implemented? (New option, new default behavior, etc.)?

New default behavior.

Please provide some example code that this change will affect:

<template>
  <div class="wrap"><slot /></div>
</template>

<MyComponent v-html="foobar" />

What does the rule currently do for this code?

It complains with vue/no-v-text-v-html-on-component.

What will the rule do after it's changed?

It does not complain. Because there is default slot defined, v-html is correctly used for the slot content and does not remove the wrap div.

@kevsommer
Copy link

The behaviour of this rule is correct in my opinion, because v-html does not use the default slot.
Instead it injects raw html in the place of the default slot, which poses a security risk, because that can lead to XSS vulnerabilities. v-html documentation

Instead you could achieve the behaviour without security risks like this:

<template>
  <div class="wrap"><slot /></div>
</template>

<MyComponent>
  {{ foobar }}
</MyComponent>

or you can pass a foobar component instead.

<template>
  <div class="wrap"><slot /></div>
</template>

<MyComponent>
  <Foobar />
</MyComponent>

@mitar
Copy link
Author

mitar commented Mar 18, 2024

The behaviour of this rule is correct in my opinion, because v-html does not use the default slot.

That is different from what I am observing in recent versions of Vue.

Instead it injects raw html in the place of the default slot, which poses a security risk, because that can lead to XSS vulnerabilities. v-html documentation

That is covered by v-html rule. Here we are talking only about vue/no-v-text-v-html-on-component which does lead to corruption of content when you have. It is triggered by v-text as well (which does not pose XSS risk). If you have:

<template>
  <div class="wrap">Something</div>
</template>

Then whole content is replaced, including wrap div. But if you have:

<template>
  <div class="wrap"><slot /></div>
</template>

my testing indicated that v-html correctly replaces <slot /> content with raw HTML (or text with v-text).

See example here:

App.vue:

<script setup>
import { ref } from 'vue'
import Comp from './Comp.vue'

const html = `<div class="inner">Inner</div>`
</script>

<template>
  <div class="component"><Comp v-html="html" /></div>
</template>

Comp.vue:

<script setup></script>

<template>
  <div class="wrap">
    <slot />
  </div>
</template>

This renders for me:

<div class="component"><div class="wrap"><div class="inner">Inner</div></div></div>

Which is what I would expect.

@FloEdelmann
Copy link
Member

Regardless, it is hard for eslint-plugin-vue to determine whether a component has slots at all, since we don't have access to other files. You can manually ignore those components using the allow option (see vue/no-v-text-v-html-on-component rule docs), or disable the rule altogether if it doesn't make sense for your project.

@mitar
Copy link
Author

mitar commented Mar 18, 2024

I see. Still, it might be useful to document when it is safe to use v-text on a component and which are the components which can be added to allow list. To me it looks like this rule catches only rare cases: when you have component without a slot. That is pretty rare if you are setting content on a component. I would even claim that this should be a separate rule: you are setting content on a component without slot, e.g., even regular <Comp>Something</Comp> would not work correctly if the component does not have a slot.

@FloEdelmann
Copy link
Member

it might be useful to document when it is safe

Sure, documentation improvement PRs are always welcome!

this rule catches only rare cases: when you have component without a slot

Hmm, without a default slot. But it is useful to always avoid the "v-html/v-text on components" pattern if you are not aware of its intricacies, as it can overwrite child components' contents. <Comp>Something</Comp> on the other hand can't, so it's a different case.

I would even claim that this should be a separate rule

Can you elaborate what you would split out to a separate rule? Note that other rules also can't know which components have (default) slots without reading multiple files.

@mitar
Copy link
Author

mitar commented Mar 18, 2024

Can you elaborate what you would split out to a separate rule? Note that other rules also can't know which components have (default) slots without reading multiple files.

I understand that it is not possible to write such a rule without reading multiple files. But, it seems to me there are three issues here:

  1. Using v-html and XSS risk (for that we have a rule).
  2. Using v-text (and also v-html, but let's focus on v-text to not conflate these two issues) on a component without a default slot - it overrides contents.
  3. Providing content for a component without a default slot in general - provided content is ignored.

I think the issue is really only 3., providing content to a component without slot is problematic, or it is ignored or it overrides existing content. So rule should warn.

  1. is already handled well.

Currently vue/no-v-text-v-html-on-component has a lot of false positives: it complains for components with a default slot. I think when it was made it might be that even for those components contents got corrupted. Today this is not the case. So vue/no-v-text-v-html-on-component is only relevant for a component which does not expect content (case 3. above) but you provide it. I would claim this is rare. This is clearly an error and it is very quick to notice it the first time you run it. It does not have much with v-html or v-text, it is about providing content to a component which does not expect it. So I wonder, how often it really is that you provide content to a component which does not expect that? Generally you read some documentation or something.

So I think vue/no-v-text-v-html-on-component as it is has many or even too many false positives.

@FloEdelmann
Copy link
Member

For reference, this is the original issue: #1724

@jacekkarczmarczyk
Copy link

Then whole content is replaced, including wrap div. But if you have:

<template>
  <div class="wrap"><slot /></div>
</template>

my testing indicated that v-html correctly replaces <slot /> content with raw HTML (or text with v-text).

Try this

<template>
  <div class="wrap">
    <div class="wrap2">
     <slot />
    </div>
  </div>
</template>

@mitar
Copy link
Author

mitar commented Mar 18, 2024

Try this

Nice. This really does not work. Thanks.

I have found only this issue about this behavior is Vue core, but it looks it is just about SSR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants