Logo
Home
Resources

Product

Custom Workflow

Resources

Blog
Youtube
Template

[Hubspot modules] HubSpot Case Study & Customer Interview Module Requirements

A module for showcasing B2B case studies, client portfolios, or success stories in a responsive, interactive slider format. Editors can easily add multiple case study cards, each with an image, tags, title, company name, and a link.

Demo Video

Over view
Code

Detail

Case Study Slider Module

This module is designed to display multiple case studies or client achievements in a visually appealing and space-efficient slider format.

Purpose of Use

  • To introduce the success stories and achievements of B2B clients in an easy-to-understand format.
  • To increase credibility and trust by showcasing a track record with various companies.
  • To effectively guide visitors to detailed case study pages.

What it can achieve

  • You can add, delete, and reorder an unlimited number of case study "cards."
  • For each card, you can set an image, title, company name, multiple tags (e.g., industry, service used), and a link to a detailed page.
  • The entire module's primary color and the font sizes for the main title, card title, company name, and tags can be customized.
  • The slider is fully responsive and automatically adjusts the number of visible cards for desktop, tablet, and mobile screens.
  • It supports intuitive navigation via buttons, pagination dots, mouse dragging, and touch swipes.

Implementation Points & Notes

  • Repeater Field: This module utilizes a repeater field for the "Case Studies" section. The group for the repeater should contain an image field, text field (title), text field (company name), another repeater field for the tags, and a link field.
  • Styling Options: Provide fields such as a color picker (for primary_color) and number fields (for font sizes) to allow for easy visual customization without needing to edit code.
  • JavaScript Dependency: The provided JavaScript handles all slider logic, including responsiveness and various input methods. Ensure it is properly loaded with the module to guarantee functionality.
  • Image Sizing: In the help text for the image field, recommend a consistent aspect ratio (e.g., 16:9) for all case study images to maintain a uniform look. The CSS uses object-fit: cover, which handles minor size variations, but consistency is best for a clean design.

‍

🛠 Implementation Points & Considerations

Field Structure

  • Section settings: Main title (e.g., "Customer Success Stories")
  • Repeater group: Repeating fields for case study cards
    • Image field (recommended size: 600x400px, for case photos or logos)
    • Text field (case title/results summary)
    • Text field (company/organization name)
    • URL field (link to detailed article/interview page)
    • Tag group (multiple tags allowed)
      • Text field (performance tags: "2x Lead Generation" etc.)

‍

[
  {
    "name": "main_title",
    "label": "メインタイトル",
    "type": "text",
    "default": "導入インタビュー"
  },
  {
    "name": "primary_color",
    "label": "プライマリーカラー",
    "type": "color",
    "default": {
      "color": "#007bff"
    }
  },
  {
    "name": "title_font_size",
    "label": "タイトルフォントサイズ(px)",
    "type": "number",
    "default": 32
  },
  {
    "name": "company_font_size",
    "label": "会社名フォントサイズ(px)",
    "type": "number",
    "default": 14
  },
  {
    "name": "description_font_size",
    "label": "説明文フォントサイズ(px)",
    "type": "number",
    "default": 16
  },
  {
    "name": "tag_font_size",
    "label": "タグフォントサイズ(px)",
    "type": "number",
    "default": 12
  },
  {
    "name": "case_studies",
    "label": "事例",
    "type": "group",
    "expanded": true,
    "occurrence": {
      "min": 1,
      "max": 20,
      "default": 3
    },
    "children": [
      {
        "name": "image",
        "label": "画像",
        "type": "image",
        "required": false,
        "resizable": true
      },
      {
        "name": "title",
        "label": "タイトル",
        "type": "text",
        "default": "事例のタイトルを入力してください",
        "required": true
      },
      {
        "name": "company_name",
        "label": "会社名",
        "type": "text",
        "default": "会社名を入力してください",
        "required": true
      },
      {
        "name": "link_url",
        "label": "リンク先URL",
        "type": "url",
        "required": false
      },
      {
        "name": "tags",
        "label": "タグ",
        "type": "group",
        "occurrence": {
          "min": 0,
          "max": 10,
          "default": 2
        },
        "children": [
          {
            "name": "tag_text",
            "label": "タグテキスト",
            "type": "text",
            "required": true,
            "help_text": "表示したいタグのテキストを入力してください"
          }
        ]
      }
    ]
  }
]

‍

Styling Configuration

  • Color fields: Primary color (for tag backgrounds, button colors)
  • Number fields: Font sizes for each element (title, company name, description, tags)
  • Layout control: Automatic responsive design using CSS Grid/Flexbox

Technical Considerations

  • Slider functionality: Vanilla JavaScript implementation, lightweight design without external dependencies
  • User experience: Arrow buttons, dot navigation, drag & swipe operations
  • Performance: Image lazy loading, smooth animations
  • Accessibility: Keyboard navigation, screen reader support
  • SEO optimization: Structured data (Review Schema) output option

📝 Use Cases

  1. B2B service case studies: Emphasize results like "300% revenue growth" or "efficiency improvements"
  2. SaaS product success stories: Appeal service value with concrete metrics and customer testimonials
  3. Consulting track record: Prove project outcomes and customer satisfaction through cases
  4. Education/training services: Showcase concrete growth and transformation of students/companies

🎨 Design Guidelines

  • Visual impact: Position performance tags in prominent colors to emphasize metrics and benefits
  • Credibility presentation: Use actual customer photos or logos to appeal authenticity
  • Readability: Organize information with appropriate spacing and font sizes
  • Consistency: Maintain unified format across all case studies

🚀 Expected Benefits

  • Improved conversion rates: Increase inquiries/applications through case study credibility
  • Sales material efficiency: Leverage website cases for sales presentations
  • SEO benefits: Increased search traffic for customer company names
  • Enhanced brand value: Strengthen industry position through accumulated success stories
  • Editing efficiency: Easy addition/updates of new cases even for non-technical users

‍

Source Code

HTML
{% set module_id = name|lower|replace(' ', '_') %}

<div class="case-study-slider" id="{{ module_id }}" 
     style="--primary-color: {{ module.primary_color.color }}; 
            --title-font-size: {{ module.title_font_size }}px;
            --company-font-size: {{ module.company_font_size }}px;
            --description-font-size: {{ module.description_font_size }}px;
            --tag-font-size: {{ module.tag_font_size }}px;">
  
  {% if module.main_title %}
    <h2 class="slider-title">{{ module.main_title }}</h2>
  {% endif %}

  <div class="slider-container">
    <div class="slider-track" id="{{ module_id }}_track">
      {% for case in module.case_studies %}
        <div class="case-card">
          {% if case.image and case.image.src %}
            <div class="case-image">
              <img src="{{ case.image.src }}" alt="{{ case.image.alt or case.title }}" loading="lazy">
            </div>
          {% else %}
            {# デバッグ用:画像がない場合のプレースホルダー #}
            <div class="case-image placeholder">
              <div class="placeholder-content">No Image</div>
            </div>
          {% endif %}
          
          <div class="case-content">
            {# タグの表示 #}
            {% if case.tags and case.tags|length > 0 %}
              <div class="tags-container">
                {% for tag in case.tags %}
                  {% if tag.tag_text %}
                    <span class="tag">{{ tag.tag_text }}</span>
                  {% endif %}
                {% endfor %}
              </div>
            {% endif %}
            
            {% if case.title %}
              <h3 class="case-title">{{ case.title }}</h3>
            {% endif %}
            
            {% if case.company_name %}
              <p class="company-name">{{ case.company_name }}</p>
            {% endif %}
            
            {% if case.link_url and case.link_url.href %}
              <a href="{{ case.link_url.href }}" class="case-link"
                 {% if case.link_url.open_in_new_tab %}target="_blank"{% endif %}>
                <svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <path d="M5 12h14M12 5l7 7-7 7"/>
                </svg>
              </a>
            {% endif %}
          </div>
        </div>
      {% endfor %}
    </div>
    
    <div class="slider-controls">
      <button class="prev-btn" data-target="{{ module_id }}_track" aria-label="前のスライド">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M19 12H5M12 19l-7-7 7-7"/>
        </svg>
      </button>
      
      <div class="pagination">
        {% for case in module.case_studies %}
          <button class="pagination-dot{% if loop.first %} active{% endif %}" 
                  data-slide="{{ loop.index0 }}" data-target="{{ module_id }}_track"></button>
        {% endfor %}
      </div>
      
      <button class="next-btn" data-target="{{ module_id }}_track" aria-label="次のスライド">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M5 12h14M12 5l7 7-7 7"/>
        </svg>
      </button>
    </div>
  </div>
</div>

‍

CSS
.case-study-slider {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.slider-title {
  font-size: var(--title-font-size, 32px);
  font-weight: bold;
  margin-bottom: 40px;
  text-align: left;
  color: var(--primary-color, #333);
}

.slider-container {
  position: relative;
  overflow: hidden;
  border-radius: 12px;
}

.slider-track {
  display: flex;
  transition: transform 0.3s ease;
  gap: 20px;
}

.case-card {
  flex: 0 0 calc(33.333% - 14px);
  background: white;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.case-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}

.case-image.placeholder {
  background-color: #f5f5f5;
  display: flex;
  align-items: center;
  justify-content: center;
}

.placeholder-content {
  color: #999;
  font-size: 14px;
}

.case-image {
  position: relative;
  height: 200px;
  overflow: hidden;
}

.case-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.case-card:hover .case-image img {
  transform: scale(1.05);
}

.case-content {
  padding: 24px;
  position: relative;
}

.tags-container {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.tag {
  background-color: var(--primary-color, #007bff);
  color: white;
  padding: 6px 12px;
  border-radius: 20px;
  font-size: var(--tag-font-size, 12px);
  font-weight: 500;
  white-space: nowrap;
}

.case-title {
  font-size: var(--description-font-size, 16px);
  font-weight: 600;
  line-height: 1.5;
  margin-bottom: 16px;
  color: #333;
  min-height: 48px;
}

.company-name {
  font-size: var(--company-font-size, 14px);
  color: #666;
  margin-bottom: 20px;
  font-weight: 500;
}

.case-link {
  position: absolute;
  bottom: 20px;
  right: 20px;
  width: 40px;
  height: 40px;
  background-color: var(--primary-color, #007bff);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  transition: all 0.3s ease;
}

.case-link:hover {
  transform: scale(1.1);
  background-color: color-mix(in srgb, var(--primary-color, #007bff) 80%, black);
}

.arrow-icon {
  width: 20px;
  height: 20px;
  color: white;
}

.slider-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  margin-top: 30px;
}

.prev-btn, .next-btn {
  width: 48px;
  height: 48px;
  border: 2px solid var(--primary-color, #007bff);
  background: transparent;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  color: var(--primary-color, #007bff);
}

.prev-btn:hover, .next-btn:hover {
  background-color: var(--primary-color, #007bff);
  color: white;
  transform: scale(1.05);
}

.prev-btn:disabled, .next-btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.prev-btn:disabled:hover, .next-btn:disabled:hover {
  background: transparent;
  color: var(--primary-color, #007bff);
  transform: none;
}

.prev-btn svg, .next-btn svg {
  width: 20px;
  height: 20px;
}

.pagination {
  display: flex;
  gap: 8px;
}

.pagination-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: none;
  background-color: #ddd;
  cursor: pointer;
  transition: all 0.3s ease;
}

.pagination-dot.active {
  background-color: var(--primary-color, #007bff);
}

.pagination-dot:hover {
  background-color: var(--primary-color, #007bff);
  opacity: 0.7;
}

/* レスポンシブデザイン */
@media (max-width: 768px) {
  .case-card {
    flex: 0 0 calc(50% - 10px);
  }
  
  .slider-title {
    font-size: calc(var(--title-font-size, 32px) * 0.8);
  }
}

@media (max-width: 480px) {
  .case-card {
    flex: 0 0 calc(100% - 0px);
  }
  
  .slider-track {
    gap: 10px;
  }
  
  .case-content {
    padding: 20px;
  }
  
  .slider-title {
    font-size: calc(var(--title-font-size, 32px) * 0.7);
    margin-bottom: 30px;
  }
}

‍

‍

‍

Javascript
document.addEventListener('DOMContentLoaded', function() {
  // すべてのスライダーを初期化
  const sliders = document.querySelectorAll('.case-study-slider');
  
  sliders.forEach(function(slider) {
    initializeSlider(slider);
  });
  
  function initializeSlider(sliderElement) {
    const track = sliderElement.querySelector('.slider-track');
    const prevBtn = sliderElement.querySelector('.prev-btn');
    const nextBtn = sliderElement.querySelector('.next-btn');
    const paginationDots = sliderElement.querySelectorAll('.pagination-dot');
    const cards = sliderElement.querySelectorAll('.case-card');
    
    if (!track || cards.length === 0) return;
    
    let currentIndex = 0;
    let cardsPerView = getCardsPerView();
    const totalCards = cards.length;
    const maxIndex = Math.max(0, totalCards - cardsPerView);
    
    // ウィンドウサイズに応じて表示カード数を決定
    function getCardsPerView() {
      const width = window.innerWidth;
      if (width <= 480) return 1;
      if (width <= 768) return 2;
      return 3;
    }
    
    // スライダーの位置を更新
    function updateSliderPosition() {
      const cardWidth = cards[0].offsetWidth;
      const gap = 20;
      const translateX = -(currentIndex * (cardWidth + gap));
      track.style.transform = `translateX(${translateX}px)`;
      
      // ボタンの状態を更新
      if (prevBtn) prevBtn.disabled = currentIndex === 0;
      if (nextBtn) nextBtn.disabled = currentIndex >= maxIndex;
      
      // ページネーションドットの状態を更新
      paginationDots.forEach(function(dot, index) {
        dot.classList.toggle('active', index === currentIndex);
      });
    }
    
    // 前のスライドに移動
    function goToPrevSlide() {
      if (currentIndex > 0) {
        currentIndex--;
        updateSliderPosition();
      }
    }
    
    // 次のスライドに移動
    function goToNextSlide() {
      if (currentIndex < maxIndex) {
        currentIndex++;
        updateSliderPosition();
      }
    }
    
    // 特定のスライドに移動
    function goToSlide(index) {
      currentIndex = Math.min(Math.max(0, index), maxIndex);
      updateSliderPosition();
    }
    
    // イベントリスナーを設定
    if (prevBtn) {
      prevBtn.addEventListener('click', goToPrevSlide);
    }
    
    if (nextBtn) {
      nextBtn.addEventListener('click', goToNextSlide);
    }
    
    paginationDots.forEach(function(dot, index) {
      dot.addEventListener('click', function() {
        goToSlide(index);
      });
    });
    
    // キーボードナビゲーション
    sliderElement.addEventListener('keydown', function(e) {
      if (e.key === 'ArrowLeft') {
        goToPrevSlide();
        e.preventDefault();
      } else if (e.key === 'ArrowRight') {
        goToNextSlide();
        e.preventDefault();
      }
    });
    
    // タッチ/スワイプサポート
    let startX = 0;
    let isDragging = false;
    
    track.addEventListener('touchstart', function(e) {
      startX = e.touches[0].clientX;
      isDragging = true;
    });
    
    track.addEventListener('touchmove', function(e) {
      if (!isDragging) return;
      e.preventDefault();
    });
    
    track.addEventListener('touchend', function(e) {
      if (!isDragging) return;
      
      const endX = e.changedTouches[0].clientX;
      const diff = startX - endX;
      
      if (Math.abs(diff) > 50) {
        if (diff > 0) {
          goToNextSlide();
        } else {
          goToPrevSlide();
        }
      }
      
      isDragging = false;
    });
    
    // マウスドラッグサポート
    track.addEventListener('mousedown', function(e) {
      startX = e.clientX;
      isDragging = true;
      track.style.cursor = 'grabbing';
      e.preventDefault();
    });
    
    document.addEventListener('mousemove', function(e) {
      if (!isDragging) return;
      e.preventDefault();
    });
    
    document.addEventListener('mouseup', function(e) {
      if (!isDragging) return;
      
      const endX = e.clientX;
      const diff = startX - endX;
      
      if (Math.abs(diff) > 50) {
        if (diff > 0) {
          goToNextSlide();
        } else {
          goToPrevSlide();
        }
      }
      
      isDragging = false;
      track.style.cursor = 'grab';
    });
    
    // リサイズ時の再計算
    window.addEventListener('resize', function() {
      const newCardsPerView = getCardsPerView();
      if (newCardsPerView !== cardsPerView) {
        cardsPerView = newCardsPerView;
        currentIndex = Math.min(currentIndex, Math.max(0, totalCards - cardsPerView));
        updateSliderPosition();
      }
    });
    
    // 初期化
    updateSliderPosition();
    track.style.cursor = 'grab';
  }
});

Related Template

Need Customization?

We can customize this sample to match your specific business requirements.

Book Free Consultation

[Hubspot modules] HubSpot Case Study & Customer Interview Module Requirements

[GAS Library] Gmail to Slack Forwarder Library

[Hubspot modules] Achievement & Feature Highlight Module

[GAS Library] Department Classification Library

[Hubspot modules] Feature Section Module

Company Info
Name : SweetsVillage .Inc
CEO :
‍
Tomoo Motoyama

HomeTemplateCustomWorkflow
Terms & ConditionsPrivacy PolicyContact us

Copyright ©SweetsVillage .Inc

Back To Top Image