Dynamic Content Rendering with Scoped Slots in Vue
Scoped slots are a powerful feature in Vue.js that allow parent components to render content provided by child components, while still having access to data and methods within the child. This challenge will task you with building a reusable Card component that utilizes scoped slots to provide flexible content rendering options for its users. Understanding and implementing scoped slots is crucial for creating highly customizable and reusable Vue components.
Problem Description
You are tasked with creating a Card component that accepts a title and a slot for the card's content. The Card component should render a basic card structure (a div with a specific class) and display the provided title. The content within the card should be rendered using a scoped slot named default. The Card component should also expose a isHighlighted prop, which, when true, adds a highlight class to the card.
Key Requirements:
- Create a
Card.vuecomponent with atitleprop (string) and anisHighlightedprop (boolean). - The component should render a
divwith the classcard. - The component should display the
titleprop within anh2element inside the card. - The component should use a scoped slot named
defaultto render the card's content. - If
isHighlightedis true, the carddivshould also have the classcard--highlighted. - The component should be written in TypeScript.
Expected Behavior:
When a parent component uses the Card component and provides a title and content via the default slot, the Card component should render a card with the title displayed and the provided content rendered within the card. The isHighlighted prop should control the presence of the card--highlighted class.
Edge Cases to Consider:
- What happens if no content is provided for the
defaultslot? The card should still render correctly with just the title. - What happens if
isHighlightedis not provided? It should default tofalse. - Ensure the TypeScript types are correctly defined for props and slot usage.
Examples
Example 1:
Input:
<template>
<Card title="My Awesome Card" isHighlighted>
<p>This is the content of the card.</p>
<button>Click Me</button>
</Card>
</template>
<script setup lang="ts">
import Card from './Card.vue';
</script>
Output:
<div class="card card--highlighted">
<h2>My Awesome Card</h2>
<p>This is the content of the card.</p>
<button>Click Me</button>
</div>
Explanation: The Card component renders with the title "My Awesome Card", the content (paragraph and button), and the card--highlighted class because isHighlighted is true.
Example 2:
Input:
<template>
<Card title="Simple Card" />
</template>
<script setup lang="ts">
import Card from './Card.vue';
</script>
Output:
<div class="card">
<h2>Simple Card</h2>
</div>
Explanation: The Card component renders with the title "Simple Card" and no highlight class because isHighlighted is not provided (defaults to false).
Example 3: (Edge Case - No Content)
Input:
<template>
<Card title="Empty Card" />
</template>
<script setup lang="ts">
import Card from './Card.vue';
</script>
Output:
<div class="card">
<h2>Empty Card</h2>
</div>
Explanation: The Card component renders with the title "Empty Card" and no highlight class, even though no content is provided for the slot.
Constraints
- The component must be written in TypeScript.
- The component must use the
definePropsandslotsAPIs for Vue 3 Composition API. - The card class should be
card. The highlighted card class should becard--highlighted. - The title element should be an
h2element. - The solution should be a single
Card.vuefile.
Notes
- Consider using the
withDefaultsoption indefinePropsto provide a default value for theisHighlightedprop. - Remember that scoped slots allow you to pass data from the child component to the slot's content. While this challenge doesn't require passing data, it's a key concept to keep in mind.
- Focus on creating a clean and well-structured component that adheres to Vue best practices.
- Test your component thoroughly with different inputs and scenarios to ensure it behaves as expected.