Because Vue scoped CSS works by adding a unique data-v-xxxxx attribute to elements in the current component's template and appending it to every CSS selector. Elements rendered by child components don't get that attribute, so the selectors don't match.
vue
<template>
<div class="wrapper">
<DatePicker />
</div>
</template>
<style scoped>
/* This won't work — .calendar-popup is inside DatePicker's template */
.wrapper .calendar-popup {
background: white;
}
</style>Generated CSS looks like .wrapper[data-v-abc123] .calendar-popup[data-v-abc123], but .calendar-popup doesn't have data-v-abc123.
How to fix it
Use the :deep() selector to pierce into child components:
vue
<style scoped>
.wrapper :deep(.calendar-popup) {
background: white;
}
.wrapper :deep(.date-input) {
border-color: blue;
}
</style>Always scope :deep() to a parent class to limit its reach:
vue
<style scoped>
/* Too broad — affects ALL .btn in any child */
:deep(.btn) { background: blue; }
/* Better — only .btn inside .wrapper */
.wrapper :deep(.btn) { background: blue; }
</style>Exception: the child's root element
A child component's root element IS affected by parent scoped CSS. Vue does this intentionally so parents can control layout (margins, positioning) of their children:
vue
<style scoped>
/* This works without :deep() — targets child's root element */
.date-picker {
margin-bottom: 1rem;
}
</style>Old syntax (don't use)
css
.parent >>> .child { } /* doesn't work with SCSS */
.parent /deep/ .child { } /* deprecated */
.parent ::v-deep .child { } /* old Vue 3 syntax */In Vue 3, :deep() is the only supported syntax.