<layout-container data-size="small" data-bg-color="brand">
  <component-card 
  data-title="This is a card component"
  data-image="https://assets.codepen.io/437758/internal/avatars/users/default.png" 
  data-image-alt="Mark Conroy's avatar from CodePen.io"
  data-description="We are reading a tutorial about how to create web components. More specifically, how to create nested web components."
  data-cta-href="https://blog.logrocket.com/"
  data-cta-text="Read more"
>
  
</component-card>
  
   <component-card 
  data-title="This is a card component"
  data-image="https://assets.codepen.io/437758/internal/avatars/users/default.png" 
  data-image-alt="Mark Conroy's avatar from CodePen.io"
  data-description="We are reading a tutorial about how to create web components. More specifically, how to create nested web components."
  data-cta-href="https://blog.logrocket.com/"
  data-cta-text="Read more"
>
  
</component-card>
  
</layout-container>

class containerComponent extends HTMLElement {
  constructor() {
    super();
    // Width
    let width;
    const width_small = "48em";
    const width_medium = "60em";
    const width_large = "80em";
    
    // Other properties
    let bgColor = "white";
    const colorBrand = "pink";
    const colorAccent = "lightgreen";
    const colorAccentContrast = "darkgreen";

    if (this.hasAttribute("data-width")) {
      let widthValue = this.getAttribute("data-width");
      widthValue === "small" ? width = width_small : "";
      widthValue === "medium" ? width = width_medium : "";
      widthValue === "large" ? width = width_large : "";
    } else {
      width = width_medium;
    }
    
    if (this.hasAttribute("data-bg-color")) {
      let bgColorValue = this.getAttribute("data-bg-color");
      bgColorValue === "brand" ? bgColor = colorBrand : "";
      bgColorValue === "accent" ? bgColor = colorAccent : "";
      bgColorValue === "accent-contrast" ? bgColor = colorAccentContrast : "";
    }

    const containerTemplate = document.createElement("template");
    containerTemplate.innerHTML = `
       <slot></slot>
    `;

    const style = document.createElement("style");
    style.textContent = `
      :host {
        display: block;
        width: 100%;
        max-width: ${width};
        margin-left: auto;
        margin-right: auto;
        background-color: ${bgColor};
      }
    `;
  
    const shadowRoot = this.attachShadow({ mode: "closed" });
    shadowRoot.appendChild(style);
    shadowRoot.appendChild(containerTemplate.content.cloneNode(true));
  }
}

customElements.define("layout-container", containerComponent);


// Create a class for the element
class Card extends HTMLElement {
  constructor() {
    super();

    this.setAttribute("role", "article");
    this.classList.add("card");

    // Title
    const title = document.createElement("h2");
    title.classList.add("card__title");
    title.textContent = this.getAttribute("data-title");

    // Description
    const description = document.createElement("div");
    description.classList.add("card__description");
    description.innerHTML = this.getAttribute("data-description");
    
    // Image
    let imageWrapper;
    if (this.hasAttribute("data-image")) {
      const image = document.createElement("img");
      image.classList.add("card__image");
      image.src = this.getAttribute("data-image");
      if (this.hasAttribute("data-image-alt")) {
        image.alt = this.getAttribute("data-image-alt");
      }
      imageWrapper = document.createElement("div");
      imageWrapper.classList.add("card__image-wrapper");
      imageWrapper.appendChild(image);
      this.appendChild(imageWrapper);
    }

    // CTA
    let ctaContainer;
    if (this.hasAttribute('data-cta-href')) {
      const cta = document.createElement("a");
      cta.classList.add("card__link");
      cta.href = this.getAttribute("data-cta-href");
      cta.textContent = this.getAttribute("data-cta-text");
      ctaContainer = document.createElement("div");
      ctaContainer.classList.add('card__cta');
      ctaContainer.appendChild(cta);
    }

    const contentContainer = document.createElement("div");
    contentContainer.classList.add("card__content");
    contentContainer.appendChild(title);
    contentContainer.appendChild(description);
    if (ctaContainer !== 'undefined') {
      contentContainer.appendChild(ctaContainer);
    }

    // Create some CSS to apply to the shadow dom
    const style = document.createElement("style");
    style.textContent = `
      :host {
        display: block;
        background: #eaeaea;
        border-radius: 10px;
        border: 1px solid black;
        max-width: 300px;
        color: #333;
      }

      .card__content {
        padding: 1rem;
      }

      .card__title {
        color: #333;
        margin-top: 0;
        line-height: 1.1;
      }

      img {
        width: 100%;
        display: block;
        border-radius: 10px 10px 0 0;
      }
      
      .card__cta {
      margin-top: 1.5rem;
      }

      .card__cta a {
        color: #eaeaea;
        display: block;
        background-color: #333;
        padding: 0.25rem 1rem;
        border-radius: 5px;
        text-align: center;
      }
    `;

    // Attach the created elements to the shadow dom
    const shadowRoot = this.attachShadow({ mode: "closed" });
    shadowRoot.appendChild(style);
    if (imageWrapper !== undefined) {
      shadowRoot.appendChild(imageWrapper);
    }
    shadowRoot.appendChild(contentContainer);
  }
}

// Define the new element
customElements.define("component-card", Card);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.