Hone logo
Hone
Problems

Building Reusable UI Elements with Vue Compound Components

Compound components are a powerful pattern in Vue.js for creating flexible and reusable UI elements. They allow you to break down complex components into smaller, manageable pieces that can be used independently or together. This challenge will test your understanding of how to implement and utilize this pattern effectively.

Problem Description

Your task is to create a set of compound components for a simple accordion interface. An accordion allows users to toggle the visibility of content panels. You need to implement this using Vue's compound component pattern, ensuring that the parent component manages the state (which panel is open) and exposes methods or slots for child components to interact with it.

Key Requirements:

  1. Accordion Component: This will be the parent component. It should manage the state of which accordion panel is currently open.
  2. AccordionItem Component: This will represent an individual item within the accordion. It should contain a header and a content area.
  3. AccordionHeader Component: This component will display the clickable header for an AccordionItem. Clicking it should toggle the visibility of its associated content.
  4. AccordionContent Component: This component will display the content of an AccordionItem. Its visibility should be controlled by the Accordion component.
  5. State Management: The Accordion component must be the sole source of truth for the currently open AccordionItem.
  6. Interactivity: Clicking an AccordionHeader should update the Accordion's state, causing the corresponding AccordionContent to show or hide.
  7. Flexibility: The Accordion should support multiple AccordionItems.
  8. TypeScript: All components and their props/events must be defined using TypeScript.

Expected Behavior:

  • When the Accordion component is rendered, by default, no items should be open.
  • Clicking an AccordionHeader should open its corresponding AccordionContent and close any previously open content.
  • Clicking an already open AccordionHeader should close its content.
  • The structure should be easily extensible, allowing you to add more AccordionItems without modifying the core Accordion logic.

Edge Cases to Consider:

  • What happens if there are no AccordionItems within an Accordion?
  • How should the components handle rapid clicks? (Though for this challenge, basic toggling is sufficient).

Examples

Example 1: Basic Accordion Usage

<!-- Parent Component -->
<template>
  <Accordion>
    <AccordionItem>
      <AccordionHeader>Section 1</AccordionHeader>
      <AccordionContent>
        Content for section 1.
      </AccordionContent>
    </AccordionItem>
    <AccordionItem>
      <AccordionHeader>Section 2</AccordionHeader>
      <AccordionContent>
        Content for section 2.
      </AccordionContent>
    </AccordionItem>
  </Accordion>
</template>

Expected Rendered Output (Initial State):

[Section 1]  (Clickable header)
[Content for section 1] (Hidden)

[Section 2]  (Clickable header)
[Content for section 2] (Hidden)

Expected Rendered Output (After clicking "Section 1"):

[Section 1]  (Clickable header)
[Content for section 1] (Visible)

[Section 2]  (Clickable header)
[Content for section 2] (Hidden)

Explanation: The Accordion component manages which item is active. When "Section 1" header is clicked, the Accordion updates its internal state to mark "Section 1" as active. This state change then tells the AccordionContent for "Section 1" to become visible and the AccordionContent for "Section 2" to remain hidden (or become hidden if it was previously visible).

Example 2: Accordion with Single Item

<!-- Parent Component -->
<template>
  <Accordion>
    <AccordionItem>
      <AccordionHeader>Just One Item</AccordionHeader>
      <AccordionContent>
        This is the only content.
      </AccordionContent>
    </AccordionItem>
  </Accordion>
</template>

Expected Rendered Output (Initial State):

[Just One Item] (Clickable header)
[This is the only content.] (Hidden)

Expected Rendered Output (After clicking "Just One Item"):

[Just One Item] (Clickable header)
[This is the only content.] (Visible)

Explanation: Even with a single item, the compound component pattern holds. The Accordion manages the state, and the AccordionHeader interacts with it to toggle the AccordionContent.

Constraints

  • Component Structure: You must adhere to the compound component structure using provide/inject or similar Vue patterns for inter-component communication.
  • State Management: The Accordion component must manage the state of the currently open item. Child components should not manage this state directly.
  • TypeScript Usage: All props, emits, and component definitions must be typed using TypeScript.
  • No Third-Party Libraries: For the core accordion logic, do not use any external UI libraries or state management solutions.

Notes

  • Think about how the Accordion component can communicate with its children about which item is currently active. provide and inject is a common and effective way to achieve this in Vue 3.
  • Consider how AccordionItem will know if it's the active item to conditionally render its AccordionContent.
  • The AccordionHeader will need a way to signal to the Accordion that it has been clicked.
  • You might want to consider using a unique identifier for each AccordionItem to track its state within the parent Accordion.
Loading editor...
typescript