Menu
📱 Lihat versi lengkap (non-AMP)
Hugo Shortcodes Components

Hugo Shortcodes Lengkap: Membuat Components Reusable

Editor: Hendra WIjaya
Update: 3 February 2026
Baca: 8 menit

Hugo Shortcodes Lengkap: Membuat Components Reusable

Shortcodes adalah fitur powerful di Hugo untuk membuat components reusable dalam content Markdown. Mereka memungkinkan Anda menyisipkan complex HTML/JSX dengan syntax sederhana di Markdown.

Apa itu Shortcodes?

Definisi

Shortcodes adalah snippets template yang bisa dipanggil dari content files untuk menambahkan fungsionalitas atau styling kompleks tanpa menulis HTML langsung di Markdown.

Mengapa Menggunakan Shortcodes?

  1. DRY Principle: Tidak mengulang kode yang sama
  2. Consistency: Format konsisten di seluruh site
  3. Simplicity: Content writers bisa menambahkan complex components
  4. Maintainability: Update satu file, efek global
  5. Security: Escape content secara otomatis

Built-in Shortcodes Hugo

1. figure

Menampilkan gambar dengan caption:

{{ < figure src="/images/photo.jpg" title="Photo Title" caption="Photo description" > }}

2. gist

Embed GitHub Gist:

{{ < gist username gist-id > }}

3. highlight

Syntax highlighting dengan options:

{{ < highlight go "linenos=table,hl_lines=2 3" > }}
package main
func main() {
    fmt.Println("Hello")
}
{{ < /highlight > }}

4. instagram

Embed Instagram post:

{{ < instagram post-id > }}

5. param

Mengakses site parameters:

Site author: {{ < param author > }}

6. ref dan relref

Internal linking dengan validasi:

[Link ke post]({{ < ref "blog/my-post.md" > }})
[Relative link]({{ < relref "my-post.md" > }})

7. tweet

Embed Twitter/X tweet:

{{ < tweet user="username" id="123456789" > }}

8. vimeo dan youtube

Embed video:

{{ < vimeo video-id > }}
{{ < youtube video-id > }}

Membuat Custom Shortcodes

Struktur Folder

layouts/
└── shortcodes/
    ├── alert.html        # Single shortcode
    ├── figure.html       # Override built-in
    ├── button.html
    ├── gallery.html
    ├── code-block.html
    └── youtube-custom.html

1. Alert Shortcode

File: layouts/shortcodes/alert.html

{{ $type := .Get "type" | default "info" }}
{{ $title := .Get "title" | default "" }}

{{ $colors := dict
  "info" "bg-blue-50 border-blue-200 text-blue-800"
  "warning" "bg-yellow-50 border-yellow-200 text-yellow-800"
  "success" "bg-green-50 border-green-200 text-green-800"
  "error" "bg-red-50 border-red-200 text-red-800"
  "tip" "bg-purple-50 border-purple-200 text-purple-800"
}}

<div class="rounded-lg border-l-4 p-4 my-6 {{ index $colors $type }}">
  {{ with $title }}
  <h4 class="font-semibold mb-2">{{ . }}</h4>
  {{ end }}
  <div class="text-sm">
    {{ .Inner | markdownify }}
  </div>
</div>

Penggunaan:

 < alert type="warning" title="Perhatian" > 
Pastikan untuk backup data sebelum melanjutkan.
 < /alert > 

 < alert type="tip" > 
Gunakan Hugo Extended untuk fitur image processing.
< /alert > 

2. Button Shortcode

File: layouts/shortcodes/button.html

{{ $url := .Get "url" | default "#" }}
{{ $text := .Get "text" | default "Click me" }}
{{ $style := .Get "style" | default "primary" }}
{{ $size := .Get "size" | default "md" }}
{{ $external := .Get "external" | default false }}

{{ $styles := dict
  "primary" "bg-blue-600 text-white hover:bg-blue-700"
  "secondary" "bg-gray-200 text-gray-800 hover:bg-gray-300"
  "outline" "border-2 border-blue-600 text-blue-600 hover:bg-blue-50"
  "danger" "bg-red-600 text-white hover:bg-red-700"
}}

{{ $sizes := dict
  "sm" "px-3 py-1.5 text-sm"
  "md" "px-4 py-2 text-base"
  "lg" "px-6 py-3 text-lg"
}}

<a href="{{ $url }}"
   class="inline-flex items-center rounded-lg font-medium transition-colors {{ index $styles $style }} {{ index $sizes $size }}"
   {{ if $external }}target="_blank" rel="noopener noreferrer"{{ end }}>
  {{ $text }}
  {{ if $external }}
  <svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
  </svg>
  {{ end }}
</a>

Penggunaan:

{{ < button url="https://gohugo.io" text="Visit Hugo Docs" style="primary" size="lg" external="true" > }}

{{ < button url="/contact" text="Contact Us" style="outline" > }}

File: layouts/shortcodes/gallery.html

{{ $folder := .Get "folder" | default "images/gallery" }}
{{ $match := .Get "match" | default "*" }}

<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 my-8">
  {{ $images := .Page.Resources.Match (printf "%s/%s" $folder $match) }}
  {{ range $images }}
  <div class="relative aspect-square overflow-hidden rounded-lg group">
    {{ $resized := .Resize "400x400" }}
    <img src="{{ $resized.RelPermalink }}"
         alt="{{ .Name }}"
         class="w-full h-full object-cover transition-transform group-hover:scale-110"
         loading="lazy">
    <div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-30 transition-opacity"></div>
  </div>
  {{ end }}
</div>

Penggunaan:

{{ < gallery folder="images/trip" match="*.jpg" > }}

4. Code Block dengan File

File: layouts/shortcodes/code-file.html

{{ $file := .Get "file" }}
{{ $lang := .Get "lang" | default "text" }}
{{ $title := .Get "title" | default $file }}

{{ $path := printf "%s" $file }}
{{ $content := readFile $path }}

<div class="code-block my-6">
  <div class="flex items-center justify-between px-4 py-2 bg-gray-800 rounded-t-lg">
    <span class="text-gray-300 text-sm font-mono">{{ $title }}</span>
    <button onclick="navigator.clipboard.writeText(this.nextElementSibling.textContent)"
            class="text-gray-400 hover:text-white text-sm">
      Copy
    </button>
  </div>
  {{ highlight $content $lang "" }}
</div>

Penggunaan:

{{ < code-file file="config.toml" lang="toml" title="hugo.toml" > }}

{{ < code-file file="layouts/_default/baseof.html" lang="html" > }}

5. YouTube Custom

File: layouts/shortcodes/youtube-custom.html

{{ $id := .Get "id" }}
{{ $title := .Get "title" | default "YouTube Video" }}
{{ $start := .Get "start" | default 0 }}
{{ $autoplay := .Get "autoplay" | default false }}

<div class="video-container my-8">
  <div class="relative w-full" style="padding-bottom: 56.25%;">
    <iframe
      class="absolute inset-0 w-full h-full rounded-lg"
      src="https://www.youtube.com/embed/{{ $id }}?start={{ $start }}{{ if $autoplay }}&autoplay=1{{ end }}"
      title="{{ $title }}"
      frameborder="0"
      allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
      allowfullscreen>
    </iframe>
  </div>
  {{ with $title }}
  <p class="text-center text-sm text-gray-600 mt-2">{{ . }}</p>
  {{ end }}
</div>

Penggunaan:

{{ < youtube-custom id="dQw4w9WgXcQ" title="Hugo Tutorial" start="30" > }}

6. Card Component

File: layouts/shortcodes/card.html

{{ $title := .Get "title" }}
{{ $image := .Get "image" }}
{{ $link := .Get "link" | default "#" }}
{{ $style := .Get "style" | default "default" }}

{{ $styles := dict
  "default" "bg-white"
  "dark" "bg-gray-800 text-white"
  "primary" "bg-blue-50 border-blue-200"
}}

<a href="{{ $link }}" class="block rounded-xl shadow-md overflow-hidden hover:shadow-xl transition-shadow {{ index $styles $style }}">
  {{ with $image }}
  <img src="{{ . }}" alt="{{ $title }}" class="w-full h-48 object-cover">
  {{ end }}
  <div class="p-6">
    <h3 class="text-xl font-semibold mb-2">{{ $title }}</h3>
    <div class="text-gray-600">
      {{ .Inner | markdownify }}
    </div>
  </div>
</a>

Penggunaan:

{{ < card title="Hugo Tutorial" image="/images/hugo.jpg" link="/tutorials/hugo" > }}
Learn how to build fast static sites with Hugo.
{{ < /card > }}

Parameter Handling

Positional vs Named Parameters

Positional (bisa semua):

<!-- shortcode: {{ < myshortcode param1 param2 > }} -->
{{ $first := .Get 0 }}
{{ $second := .Get 1 }}

Named (lebih readable):

<!-- shortcode: {{ < myshortcode key="value" > }} -->
{{ $value := .Get "key" }}

Mixed:

<!-- {{ < myshortcode "value1" key="value2" > }} -->
{{ $first := .Get 0 }}
{{ $second := .Get "key" }}

Default Values

{{ $title := .Get "title" | default "Untitled" }}
{{ $show := .Get "show" | default true }}
{{ $count := .Get "count" | default 5 }}

Boolean Parameters

{{ $external := false }}
{{ if eq (.Get "external") "true" }}
  {{ $external = true }}
{{ end }}

Inner Content

Simple Shortcodes

{{ < shortcode param="value" > }}

Paired Shortcodes

{{ < shortcode > }}
Inner content here with **markdown** support.
{{ < /shortcode > }}

Template:

<div class="box">
  {{ .Inner | markdownify }}
</div>

Conditional Inner Content

{{ with .Inner }}
  <div class="content">
    {{ . | markdownify }}
  </div>
{{ else }}
  <p class="placeholder">No content provided</p>
{{ end }}

Advanced Shortcodes

1. Tabs Component

File: layouts/shortcodes/tabs.html

<div class="tabs my-6" x-data="{ activeTab: 0 }">
  <div class="flex border-b border-gray-200">
    {{ $tabs := split (.Inner) "<!-- tab -->" }}
    {{ range $index, $tab := after 1 $tabs }}
      {{ $parts := split $tab "<!-- /tab -->" }}
      {{ $title := index (split (index $parts 0) " ") 0 }}
      <button
        @click="activeTab = {{ $index }}"
        :class="{ 'border-blue-500 text-blue-600': activeTab === {{ $index }} }"
        class="px-4 py-2 font-medium text-gray-500 hover:text-gray-700 border-b-2 border-transparent">
        {{ $title }}
      </button>
    {{ end }}
  </div>

  <div class="py-4">
    {{ range $index, $tab := after 1 $tabs }}
      {{ $parts := split $tab "<!-- /tab -->" }}
      {{ $content := index $parts 0 }}
      <div x-show="activeTab === {{ $index }}" class="prose">
        {{ $content | markdownify }}
      </div>
    {{ end }}
  </div>
</div>

Penggunaan:

{{ < tabs > }}
<!-- tab macOS -->
### Installation on macOS
```bash
brew install hugo

Installation on Windows

choco install hugo-extended

Installation on Linux

sudo apt install hugo

{{ < /tabs > }}


### 2. Details/Summary (Accordion)

**File: `layouts/shortcodes/details.html`**

```html
{{ $summary := .Get "summary" | default "Details" }}
{{ $open := .Get "open" | default false }}

<details class="my-4 p-4 bg-gray-50 rounded-lg" {{ if $open }}open{{ end }}>
  <summary class="font-semibold cursor-pointer">{{ $summary }}</summary>
  <div class="mt-4 prose">
    {{ .Inner | markdownify }}
  </div>
</details>

Penggunaan:

{{ < details summary="Click to expand" open="true" > }}
Hidden content that can be toggled.
{{ < /details > }}

3. Book Rating

File: layouts/shortcodes/book.html

{{ $title := .Get "title" }}
{{ $author := .Get "author" }}
{{ $rating := .Get "rating" | default 0 }}
{{ $cover := .Get "cover" }}
{{ $link := .Get "link" }}

<div class="flex gap-4 my-6 p-4 bg-gray-50 rounded-lg">
  {{ with $cover }}
  <img src="{{ . }}" alt="{{ $title }}" class="w-24 h-36 object-cover rounded shadow">
  {{ end }}

  <div class="flex-1">
    <h3 class="font-bold text-lg">{{ $title }}</h3>
    <p class="text-gray-600">{{ $author }}</p>

    <div class="flex items-center gap-1 mt-2">
      {{ range seq 5 }}
        {{ if le . $rating }}
        <svg class="w-5 h-5 text-yellow-400 fill-current" viewBox="0 0 20 20">
          <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
        </svg>
        {{ else }}
        <svg class="w-5 h-5 text-gray-300 fill-current" viewBox="0 0 20 20">
          <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
        </svg>
        {{ end }}
      {{ end }}
    </div>

    {{ with $link }}
    <a href="{{ . }}" class="text-blue-600 hover:underline mt-2 inline-block">View on Amazon →</a>
    {{ end }}
  </div>
</div>

Penggunaan:

{{ < book title="Atomic Habits" author="James Clear" rating="5" cover="/images/atomic-habits.jpg" link="https://amazon.com/..." > }}

Shortcode Security

XSS Prevention

<!-- Selalu escape output -->
{{ $title := .Get "title" | htmlEscape }}

<!-- Atau gunakan safeHTML dengan hati-hati -->
{{ $html := .Get "html" | safeHTML }}

Markdownify vs HTML

<!-- Use markdownify untuk inner content -->
{{ .Inner | markdownify }}

<!-- Use .RenderString untuk custom markdown -->
{{ .RenderString .Inner }}

Best Practices

1. Naming Conventions

  • Descriptive names: youtube-custom lebih baik dari yt
  • Consistent naming: alert, button, card
  • Avoid conflicts: Jangan override built-in kecuali perlu

2. Documentation

Tambahkan docs di shortcode file:

<!--
Usage:
{{ < alert type="warning" title="Title" > }}
Content here
{{ < /alert > }}

Parameters:
- type: info|warning|success|error|tip (default: info)
- title: string (optional)
-->

3. Default Values

Selalu berikan default untuk required parameters:

{{ $title := .Get "title" | default "Untitled" }}
{{ $style := .Get "style" | default "default" }}

4. Validation

Check parameters sebelum digunakan:

{{ if .Get "title" }}
  <!-- Render dengan title -->
{{ else }}
  {{ errorf "Shortcode 'card': missing required parameter 'title'" }}
{{ end }}

Kesimpulan

Shortcodes adalah fitur powerful Hugo untuk:

Reusability: Components sekali buat, pakai berulang kali
Consistency: Format uniform di seluruh site
Simplicity: Markdown tetap bersih dan readable
Flexibility: Kustomisasi tanpa batas
Maintainability: Update global dengan edit satu file

Gunakan shortcodes untuk:

  • Complex layouts
  • Embeds (YouTube, CodePen, dll)
  • Styled components (alerts, buttons, cards)
  • Content variations (tabs, accordions)

Artikel Terkait

Bagikan:

Link Postingan: https://www.tirinfo.com/hugo-shortcodes-lengkap/