Salin dan Bagikan
Tutorial Hugo Partials: Membuat Reusable Template Components - Tutorial lengkap Hugo partials untuk membuat reusable template components. Best practices, parameter …

Tutorial Hugo Partials: Membuat Reusable Template Components

Tutorial Hugo Partials: Membuat Reusable Template Components

Partials adalah komponen reusable dalam Hugo templates yang memungkinkan Anda memecah template kompleks menjadi bagian-bagian yang manageable dan reusable.

Apa itu Partials?

Definisi

Partials adalah template snippets yang bisa dipanggil dari template lain menggunakan fungsi partial. Mereka adalah building blocks untuk membangun layouts yang kompleks.

Mengapa Menggunakan Partials?

  1. DRY Principle: Tulis sekali, pakai di banyak tempat
  2. Modularity: Template lebih mudah di-maintain
  3. Reusability: Komponen bisa dipakai di berbagai layout
  4. Caching: Partials bisa di-cache untuk performa
  5. Testing: Lebih mudah test komponen individual

Struktur Partials

Directory Structure

layouts/
└── partials/
    ├── head.html              # HTML head section
    ├── header.html            # Site header
    ├── footer.html            # Site footer
    ├── navigation.html        # Navigation menu
    ├── sidebar.html           # Sidebar content
    ├── pagination.html        # Pagination
    ├── seo-meta.html          # SEO meta tags
    ├── schema-jsonld.html     # Schema.org JSON-LD
    ├── opengraph.html         # Open Graph tags
    ├── twitter-card.html      # Twitter Card meta
    ├── analytics.html         # Analytics scripts
    ├── comments.html          # Comments section
    ├── related-posts.html     # Related posts
    ├── breadcrumbs.html       # Breadcrumb navigation
    ├── toc.html               # Table of Contents
    ├── social-share.html      # Social sharing buttons
    ├── author-box.html        # Author bio box
    ├── newsletter.html        # Newsletter signup
    ├── search.html            # Search form
    ├── svg/
    │   ├── icon-facebook.html
    │   ├── icon-twitter.html
    │   └── icon-github.html
    └── cards/
        ├── post-card.html
        └── author-card.html

Basic Partials

1. Head Partial

File: layouts/partials/head.html

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} | {{ .Site.Title }}{{ end }}</title>

<!-- CSS -->
{{ $css := resources.Get "css/main.css" }}
{{ $css = $css | resources.PostCSS }}
{{ if hugo.IsProduction }}
  {{ $css = $css | resources.Minify | resources.Fingerprint }}
  <link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}">
{{ else }}
  <link rel="stylesheet" href="{{ $css.RelPermalink }}">
{{ end }}

<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="/favicon.ico">

<!-- Preconnect -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- Canonical -->
<link rel="canonical" href="{{ .Permalink }}">

<!-- RSS -->
{{ range .AlternativeOutputFormats }}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink }}" title="{{ $.Site.Title }}">
{{ end }}

Penggunaan di baseof.html:

<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
<head>
  {{ partial "head.html" . }}
</head>
<body>
  {{ block "main" . }}{{ end }}
</body>
</html>

2. Header Partial

File: layouts/partials/header.html

<header class="bg-white shadow-sm sticky top-0 z-50">
  <nav class="container mx-auto px-4">
    <div class="flex justify-between items-center h-16">
      <!-- Logo -->
      <a href="{{ .Site.Home.RelPermalink }}" class="text-xl font-bold text-gray-900">
        {{ .Site.Title }}
      </a>
      
      <!-- Desktop Navigation -->
      <div class="hidden md:flex items-center space-x-8">
        {{ range .Site.Menus.main }}
        <a href="{{ .URL }}" class="text-gray-600 hover:text-gray-900 transition-colors">
          {{ .Name }}
        </a>
        {{ end }}
        
        <!-- Search Toggle -->
        <button id="search-toggle" class="p-2 text-gray-600 hover:text-gray-900">
          {{ partial "svg/icon-search.html" . }}
        </button>
      </div>
      
      <!-- Mobile Menu Button -->
      <button id="mobile-menu-btn" class="md:hidden p-2">
        {{ partial "svg/icon-menu.html" . }}
      </button>
    </div>
  </nav>
  
  <!-- Mobile Menu (hidden by default) -->
  <div id="mobile-menu" class="hidden md:hidden bg-white border-t">
    {{ range .Site.Menus.main }}
    <a href="{{ .URL }}" class="block px-4 py-3 text-gray-600 hover:bg-gray-50">
      {{ .Name }}
    </a>
    {{ end }}
  </div>
</header>

File: layouts/partials/footer.html

<footer class="bg-gray-900 text-white py-12">
  <div class="container mx-auto px-4">
    <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
      <!-- Brand -->
      <div>
        <h3 class="text-lg font-semibold mb-4">{{ .Site.Title }}</h3>
        <p class="text-gray-400">{{ .Site.Params.description }}</p>
      </div>
      
      <!-- Quick Links -->
      <div>
        <h4 class="font-semibold mb-4">Menu</h4>
        <ul class="space-y-2">
          {{ range .Site.Menus.footer }}
          <li>
            <a href="{{ .URL }}" class="text-gray-400 hover:text-white transition-colors">
              {{ .Name }}
            </a>
          </li>
          {{ end }}
        </ul>
      </div>
      
      <!-- Social -->
      <div>
        <h4 class="font-semibold mb-4">Follow Us</h4>
        <div class="flex space-x-4">
          {{ range .Site.Params.social }}
          <a href="{{ .url }}" class="text-gray-400 hover:text-white transition-colors" aria-label="{{ .name }}">
            {{ partial (printf "svg/icon-%s.html" .icon) . }}
          </a>
          {{ end }}
        </div>
      </div>
    </div>
    
    <div class="mt-8 pt-8 border-t border-gray-800 text-center text-gray-400">
      <p>&copy; {{ now.Year }} {{ .Site.Title }}. All rights reserved.</p>
    </div>
  </div>
</footer>

Partials dengan Parameters

Passing Parameters

Cara 1: Single Parameter (Context)

<!-- Panggil partial dengan context -->
{{ partial "card.html" . }}

<!-- Atau dengan context berbeda -->
{{ partial "card.html" $post }}

Cara 2: Multiple Parameters (Dict)

<!-- Passing multiple parameters -->
{{ partial "card.html" (dict "title" "My Title" "image" "/img.jpg" "link" "/page") }}

4. Card Partial dengan Parameters

File: layouts/partials/cards/post-card.html

{{ $title := .title }}
{{ $image := .image }}
{{ $link := .link }}
{{ $date := .date }}
{{ $summary := .summary }}
{{ $categories := .categories }}

<article class="bg-white rounded-lg shadow-sm overflow-hidden hover:shadow-md transition-shadow">
  {{ with $image }}
  <a href="{{ $link }}" class="block">
    <img src="{{ . }}" alt="{{ $title }}" class="w-full h-48 object-cover">
  </a>
  {{ end }}
  
  <div class="p-6">
    {{ with $categories }}
    <div class="flex gap-2 mb-3">
      {{ range . }}
      <span class="text-xs font-medium text-blue-600 bg-blue-50 px-2 py-1 rounded">
        {{ . }}
      </span>
      {{ end }}
    </div>
    {{ end }}
    
    <h3 class="text-xl font-semibold mb-2">
      <a href="{{ $link }}" class="text-gray-900 hover:text-blue-600 transition-colors">
        {{ $title }}
      </a>
    </h3>
    
    {{ with $date }}
    <time class="text-sm text-gray-500 mb-3 block" datetime="{{ . }}">
      {{ dateFormat "January 2, 2006" . }}
    </time>
    {{ end }}
    
    {{ with $summary }}
    <p class="text-gray-600 line-clamp-3">{{ . }}</p>
    {{ end }}
  </div>
</article>

Penggunaan:

{{ range .Pages }}
  {{ partial "cards/post-card.html" (dict 
    "title" .Title
    "image" .Params.image
    "link" .RelPermalink
    "date" .Date
    "summary" (.Description | default .Summary)
    "categories" .Params.categories
  ) }}
{{ end }}

5. SEO Meta Partial

File: layouts/partials/seo-meta.html

{{ $title := .title | default .Site.Title }}
{{ $description := .description | default .Site.Params.description }}
{{ $image := .image | default .Site.Params.defaultImage }}
{{ $url := .url | default .Permalink }}
{{ $type := .type | default "website" }}

<!-- Basic Meta -->
<meta name="description" content="{{ $description }}">
<meta name="author" content="{{ .Site.Params.author }}">

<!-- Open Graph -->
<meta property="og:title" content="{{ $title }}">
<meta property="og:description" content="{{ $description }}">
<meta property="og:type" content="{{ $type }}">
<meta property="og:url" content="{{ $url }}">
<meta property="og:image" content="{{ $image | absURL }}">
<meta property="og:site_name" content="{{ .Site.Title }}">

<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ $title }}">
<meta name="twitter:description" content="{{ $description }}">
<meta name="twitter:image" content="{{ $image | absURL }}">
{{ with .Site.Params.twitter }}
<meta name="twitter:site" content="@{{ . }}">
{{ end }}

Penggunaan:

<!-- Homepage -->
{{ partial "seo-meta.html" (dict 
  "title" .Site.Title
  "description" .Site.Params.description
  "type" "website"
) }}

<!-- Article -->
{{ partial "seo-meta.html" (dict 
  "title" .Title
  "description" (.Description | default .Summary)
  "image" .Params.image
  "type" "article"
) }}

Conditional Partials

6. Breadcrumbs dengan Kondisi

File: layouts/partials/breadcrumbs.html

{{ if not .IsHome }}
<nav aria-label="Breadcrumb" class="py-4">
  <ol class="flex items-center space-x-2 text-sm text-gray-600">
    <li>
      <a href="{{ .Site.Home.RelPermalink }}" class="hover:text-gray-900">Home</a>
    </li>
    
    {{ if .Section }}
    <li>
      <svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
        <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
      </svg>
    </li>
    <li>
      <a href="/{{ .Section }}" class="hover:text-gray-900 capitalize">{{ .Section }}</a>
    </li>
    {{ end }}
    
    {{ if and .Parent (ne .Parent .Site.Home) }}
    <li>
      <svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
        <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
      </svg>
    </li>
    <li>
      <a href="{{ .Parent.RelPermalink }}" class="hover:text-gray-900">{{ .Parent.Title }}</a>
    </li>
    {{ end }}
    
    <li>
      <svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
        <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
      </svg>
    </li>
    <li class="text-gray-900 font-medium" aria-current="page">
      {{ .Title }}
    </li>
  </ol>
</nav>
{{ end }}

Partial Caching

Caching untuk Performa

<!-- Tanpa cache - diproses setiap kali dipanggil -->
{{ partial "navigation.html" . }}

<!-- Dengan cache - diproses sekali dan di-cache -->
{{ partialCached "navigation.html" . .RelPermalink }}

When to Use Caching

Use partialCached untuk:

  • Navigation menus
  • Footer content
  • Sidebars
  • Social links
  • Analytics scripts

Don’t cache untuk:

  • Content spesifik per page
  • Dynamic data
  • Time-sensitive information

7. Cached Navigation

{{ partialCached "navigation.html" . .Site.Language.Lang }}

Cache key berdasarkan language untuk multilingual sites.

Advanced Patterns

8. Partial dengan Return Value

Partials bisa return values dengan return statement (Hugo 0.143+):

File: layouts/partials/functions/format-date.html

{{ $format := .format | default "January 2, 2006" }}
{{ $date := .date }}
{{ return $date.Format $format }}

Penggunaan:

{{ $formatted := partial "functions/format-date.html" (dict "date" .Date "format" "Jan 2, 2006") }}
<time>{{ $formatted }}</time>

9. Partial untuk SVG Icons

File: layouts/partials/svg/icon-github.html

<svg class="{{ .class | default "w-5 h-5" }}" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
  <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path>
</svg>

Penggunaan:

{{ partial "svg/icon-github.html" (dict "class" "w-6 h-6 text-gray-600") }}

Best Practices

1. Naming Conventions

  • Descriptive: post-card.html lebih baik dari card.html
  • Consistent: Gunakan prefix untuk grouping
  • Kebab-case: my-partial.html

2. Parameter Validation

{{ if not .title }}
  {{ errorf "Partial 'card' requires 'title' parameter" }}
{{ end }}

3. Default Values

{{ $class := .class | default "bg-white" }}
{{ $showImage := .showImage | default true }}

4. Documentation

<!--
Partial: cards/post-card.html

Parameters:
  - title (required): Post title
  - image (optional): Featured image URL
  - link (required): Post URL
  - date (optional): Publish date
  - summary (optional): Post summary
  - categories (optional): Array of categories

Usage:
  {{ partial "cards/post-card.html" (dict "title" .Title "link" .RelPermalink) }}
-->

5. Scope Management

<!-- Inside partial, use . untuk akses parameter -->
{{ $title := .title }}

<!-- Untuk akses global site data -->
{{ $site := site }}
{{ $site.Title }}

Common Partials Library

Analytics Partial

{{ if hugo.IsProduction }}
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ .Site.Params.googleAnalytics }}"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', '{{ .Site.Params.googleAnalytics }}');
</script>
{{ end }}

Comments Partial

{{ if and .Site.Params.disqus (not .Site.IsServer) }}
<div id="disqus_thread"></div>
<script>
  var disqus_config = function () {
    this.page.url = "{{ .Permalink }}";
    this.page.identifier = "{{ .RelPermalink }}";
  };
</script>
{{ end }}

Table of Contents Partial

{{ if .TableOfContents }}
<aside class="toc">
  <h3>Table of Contents</h3>
  {{ .TableOfContents }}
</aside>
{{ end }}

Kesimpulan

Hugo partials adalah tools powerful untuk:

Modularity: Break down templates kompleks
Reusability: Komponen dipakai berulang kali
Maintainability: Update sekali, efek global
Performance: Caching untuk speed
Organization: Struktur template yang bersih

Gunakan partials untuk semua komponen reusable dan nikmati workflow development yang lebih efisien.

Artikel Terkait

Link Postingan : https://www.tirinfo.com/tutorial-hugo-partials/

Hendra WIjaya
Tirinfo
8 minutes.
3 February 2026