Custom Templates: Board index template
Customizing the board index template allows you to further style your forum to your preference. Below a few examples:
Template:
<div class="bx">
{{#each categories}}
<div class="bx-cat">
<div class="bx-cat-head">
<a href="{{ this.url }}" class="bx-cat-title">{{ this.name }}</a>
<span class="bx-cat-line"></span>
</div>
<div class="bx-grid">
{{#each this.forums}}
<div class="bx-card{{#unless this.is_read}} bx-card--unread{{/unless}}">
<div class="bx-top">
<span class="bx-ico">
{{#if this.marker_image_url}}<img src="{{ this.marker_image_url }}" alt="{{ this.name }}" />{{else}}<span class="{{ this.marker_icon | default:fa-regular fa-comments }}"></span>{{/if}}
</span>
{{#unless this.is_read}}<span class="bx-new">New</span>{{/unless}}
</div>
<div class="bx-name"><a href="{{ this.url }}">{{ this.name }}</a></div>
<div class="bx-desc">{{{ this.description }}}</div>
{{#if this.subforums}}
<div class="bx-subs">
{{#each this.subforums}}<a class="bx-sub{{#unless this.is_read}} bx-sub--unread{{/unless}}" href="{{ this.url }}">{{ this.name }}</a>{{/each}}
</div>
{{/if}}
<div class="bx-meta">
<span class="bx-chip"><span class="fa-regular fa-comments"></span> {{ this.topics_count }}</span>
<span class="bx-chip"><span class="fa-regular fa-message"></span> {{ this.replies_count }}</span>
</div>
{{#if this.last_post.author}}
<div class="bx-last">
<span class="bx-last-av"><img src="{{ this.last_post.avatar_url }}" alt="{{ this.last_post.author }}" /></span>
<span class="bx-last-txt">
<a href="{{ this.last_post.url }}">{{ this.last_post.title | limit:34 }}</a>
<span class="bx-last-meta">{{ this.last_post.author }} · {{ this.last_post.date }}</span>
</span>
</div>
{{else}}
<div class="bx-last bx-last--empty">No posts yet</div>
{{/if}}
</div>
{{/each}}
</div>
</div>
{{/each}}
<div class="bx-stats">
<span class="bx-stat"><span class="fa-regular fa-comments"></span> <b>{{ stats.topics }}</b> topics</span>
<span class="bx-stat"><span class="fa-regular fa-message"></span> <b>{{ stats.replies }}</b> posts</span>
<span class="bx-stat"><span class="fa-regular fa-user"></span> <b>{{ stats.members }}</b> members</span>
<span class="bx-stat"><span class="bx-pulse"></span> <b>{{ stats.online }}</b> online</span>
<span class="bx-stat bx-stat--right">Newest: <a href="{{ stats.latest_member_url }}">{{ stats.latest_member }}</a></span>
</div>
</div>CSS:
.bx-cat + .bx-cat { margin-top: 1.6rem; }
.bx-cat-head { display: flex; align-items: center; gap: 0.8rem; margin-bottom: 0.7rem; }
.bx-cat-title { font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.16em; color: inherit; text-decoration: none; opacity: 0.85; }
.bx-cat-title:hover { color: var(--fs-panel-footer-accent, inherit); opacity: 1; }
.bx-cat-line { flex: 1; height: 1px; background: linear-gradient(90deg, var(--fs-panel-footer-accent, rgba(128,128,128,0.4)), transparent); }
.bx-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 0.8rem; }
.bx-card { display: flex; flex-direction: column; padding: 0.9rem 0.95rem 0; background: var(--fs-panel-bg, rgba(128,128,128,0.05)); border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.2)); border-radius: 0.8rem; transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease; }
.bx-card:hover { transform: translateY(-3px); border-color: var(--fs-panel-footer-accent, rgba(128,128,128,0.4)); box-shadow: 0 10px 26px rgba(0, 0, 0, 0.12); }
.bx-card--unread { border-color: var(--fs-panel-footer-accent, rgba(128,128,128,0.45)); box-shadow: inset 3px 0 0 var(--fs-panel-footer-accent, transparent); }
.bx-top { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 0.6rem; }
.bx-ico { display: flex; align-items: center; justify-content: center; width: 2.6rem; height: 2.6rem; border-radius: 0.6rem; background: var(--fs-panel-section-bg, rgba(128,128,128,0.12)); color: var(--fs-panel-footer-accent, inherit); font-size: 1.05rem; }
.bx-ico img { width: 2.6rem; height: 2.6rem; object-fit: contain; border-radius: 0.6rem; }
.bx-new { font-size: 0.56rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.1em; color: #fff; background: var(--fs-panel-footer-accent, #35a377); border-radius: 999px; padding: 0.2rem 0.55rem; }
.bx-name a { font-size: 0.95rem; font-weight: 700; color: inherit; text-decoration: none; }
.bx-name a:hover { color: var(--fs-panel-footer-accent, inherit); }
.bx-card--unread .bx-name a { color: var(--fs-panel-footer-accent, inherit); }
.bx-desc { font-size: 0.78rem; opacity: 0.68; line-height: 1.45; margin-top: 0.25rem; }
.bx-desc p { margin: 0; }
.bx-subs { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.55rem; }
.bx-sub { font-size: 0.68rem; padding: 0.16rem 0.5rem; border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.25)); border-radius: 999px; color: inherit; text-decoration: none; opacity: 0.75; }
.bx-sub:hover { border-color: var(--fs-panel-footer-accent, currentColor); opacity: 1; }
.bx-sub--unread { font-weight: 700; opacity: 1; border-color: var(--fs-panel-footer-accent, rgba(128,128,128,0.4)); }
.bx-meta { display: flex; gap: 0.4rem; margin-top: 0.7rem; }
.bx-chip { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.7rem; font-weight: 600; padding: 0.22rem 0.55rem; border-radius: 999px; background: var(--fs-panel-section-bg, rgba(128,128,128,0.1)); }
.bx-chip .fa-regular, .bx-chip .fa-solid { font-size: 0.66rem; opacity: 0.7; }
.bx-last { display: flex; align-items: center; gap: 0.5rem; margin: 0.75rem -0.95rem 0; padding: 0.6rem 0.95rem; border-top: 1px solid var(--fs-forum-divider, rgba(128,128,128,0.15)); min-width: 0; }
.bx-last-av { flex-shrink: 0; width: 1.6rem; height: 1.6rem; border-radius: 50%; overflow: hidden; line-height: 0; }
.bx-last-av img { width: 100%; height: 100%; object-fit: cover; }
.bx-last-txt { display: flex; flex-direction: column; min-width: 0; }
.bx-last-txt a { font-size: 0.75rem; font-weight: 600; color: inherit; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bx-last-txt a:hover { color: var(--fs-panel-footer-accent, inherit); }
.bx-last-meta { font-size: 0.66rem; opacity: 0.55; }
.bx-last--empty { font-size: 0.72rem; font-style: italic; opacity: 0.5; }
.bx-stats { display: flex; flex-wrap: wrap; align-items: center; gap: 1.4rem; margin-top: 1.6rem; padding: 0.7rem 1rem; background: var(--fs-panel-bg, rgba(128,128,128,0.05)); border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.2)); border-radius: 0.8rem; font-size: 0.78rem; }
.bx-stat { display: inline-flex; align-items: center; gap: 0.4rem; opacity: 0.85; }
.bx-stat b { font-weight: 800; }
.bx-stat a { color: var(--fs-panel-footer-accent, inherit); text-decoration: none; font-weight: 700; }
.bx-stat--right { margin-left: auto; }
.bx-pulse { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--fs-online-active, #30a661); animation: bxPulse 1.8s ease-in-out infinite; }
@keyframes bxPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
@media (prefers-reduced-motion: reduce) { .bx-pulse, .bx-card { animation: none; transition: none; } }
@media (max-width: 640px) { .bx-grid { grid-template-columns: 1fr; } .bx-stat--right { margin-left: 0; } }
Template:
<div class="at">
{{#each categories}}
<div class="at-cat">
<div class="at-head">
<a href="{{ this.url }}" class="at-title">{{ this.name }}</a>
<span class="at-rule"></span>
</div>
<div class="at-grid">
{{#each this.forums}}
<div class="at-row{{#unless this.is_read}} at-row--unread{{/unless}}">
<span class="at-tile">
{{#if this.marker_image_url}}
<img src="{{ this.marker_image_url }}" alt="{{ this.name }}" />
{{else}}
<span class="{{ this.marker_icon | default:fa-regular fa-comments }}"></span>
{{/if}}
</span>
<div class="at-body">
<div class="at-name">
<a href="{{ this.url }}">{{ this.name }}</a>
{{#unless this.is_read}}<span class="at-dot"></span>{{/unless}}
</div>
<div class="at-desc">{{{ this.description }}}</div>
<div class="at-meta"><b>{{ this.topics_count }}</b> topics <span class="at-sep">·</span> <b>{{ this.replies_count }}</b> replies</div>
{{#if this.subforums}}
<div class="at-subs">
{{#each this.subforums}}
<a href="{{ this.url }}" class="at-sub{{#unless this.is_read}} at-sub--unread{{/unless}}">{{ this.name }}</a>
{{/each}}
</div>
{{/if}}
{{#if this.last_post.author}}
<div class="at-last">
<img src="{{ this.last_post.avatar_url }}" alt="{{ this.last_post.author }}" />
<span class="at-last-txt">
<a href="{{ this.last_post.url }}">{{ this.last_post.title | limit:38 }}</a>
<span class="at-last-meta">{{ this.last_post.author }} <span class="at-sep">·</span> {{ this.last_post.date }}</span>
</span>
</div>
{{/if}}
</div>
</div>
{{/each}}
</div>
</div>
{{/each}}
<div class="at-stats">
<span class="at-cell"><b>{{ stats.topics }}</b><span>Topics</span></span>
<span class="at-cell"><b>{{ stats.replies }}</b><span>Posts</span></span>
<span class="at-cell"><b>{{ stats.members }}</b><span>Members</span></span>
<span class="at-cell"><b>{{ stats.online }}</b><span>Online</span></span>
<span class="at-cell at-cell--new"><b><a href="{{ stats.latest_member_url }}">{{ stats.latest_member }}</a></b><span>Newest member</span></span>
</div>
</div>CSS:
.at-cat + .at-cat { margin-top: 1.8rem; }
.at-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 0.85rem; }
.at-title { font-size: 1.18rem; font-weight: 800; letter-spacing: -0.015em; color: inherit; text-decoration: none; }
.at-title:hover { color: var(--fs-panel-footer-accent, inherit); }
.at-rule { flex: 1; height: 3px; border-radius: 999px; background: linear-gradient(90deg, var(--fs-panel-footer-accent, rgba(128,128,128,0.4)), transparent 55%); }
.at-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem; }
.at-row { display: flex; gap: 0.85rem; padding: 0.95rem 1rem; background: var(--fs-panel-bg, rgba(128,128,128,0.04)); border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.2)); border-radius: 0.65rem; transition: border-color 0.14s ease, box-shadow 0.14s ease; }
.at-row:hover { border-color: var(--fs-panel-footer-accent, rgba(128,128,128,0.45)); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.07); }
.at-row--unread { box-shadow: inset 3px 0 0 var(--fs-panel-footer-accent, currentColor); }
.at-tile { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 2.7rem; height: 2.7rem; border-radius: 0.55rem; background: var(--fs-panel-section-bg, rgba(128,128,128,0.1)); color: var(--fs-panel-footer-accent, inherit); font-size: 1.05rem; }
.at-tile img { width: 2.7rem; height: 2.7rem; object-fit: contain; border-radius: 0.55rem; }
.at-body { flex: 1; min-width: 0; }
.at-name { display: flex; align-items: center; gap: 0.45rem; }
.at-name a { font-size: 0.98rem; font-weight: 700; letter-spacing: -0.01em; color: var(--fs-forum-link-color, inherit); text-decoration: none; }
.at-name a:hover { color: var(--fs-panel-footer-accent, inherit); }
.at-row--unread .at-name a { color: var(--fs-panel-footer-accent, inherit); }
.at-dot { width: 0.45rem; height: 0.45rem; border-radius: 50%; background: var(--fs-panel-footer-accent, currentColor); }
.at-desc { font-size: 0.77rem; opacity: 0.62; line-height: 1.45; margin-top: 0.1rem; }
.at-desc p { margin: 0; }
.at-meta { font-size: 0.72rem; opacity: 0.75; margin-top: 0.35rem; font-variant-numeric: tabular-nums; }
.at-meta b { font-weight: 700; }
.at-sep { opacity: 0.45; margin: 0 0.15rem; }
.at-subs { display: flex; flex-wrap: wrap; gap: 0.15rem 0.8rem; margin-top: 0.3rem; font-size: 0.72rem; }
.at-sub { color: inherit; opacity: 0.65; text-decoration: none; }
.at-sub:hover { opacity: 1; text-decoration: underline; }
.at-sub--unread { opacity: 1; font-weight: 700; color: var(--fs-panel-footer-accent, inherit); }
.at-last { display: flex; align-items: center; gap: 0.45rem; margin-top: 0.55rem; padding-top: 0.55rem; border-top: 1px solid var(--fs-forum-divider, rgba(128,128,128,0.13)); min-width: 0; }
.at-last img { flex-shrink: 0; width: 1.45rem; height: 1.45rem; border-radius: 50%; object-fit: cover; }
.at-last-txt { display: flex; flex-direction: column; min-width: 0; }
.at-last-txt a { font-size: 0.75rem; font-weight: 600; color: inherit; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.at-last-txt a:hover { color: var(--fs-panel-footer-accent, inherit); }
.at-last-meta { font-size: 0.65rem; opacity: 0.55; }
.at-stats { display: flex; flex-wrap: wrap; margin-top: 1.8rem; border: 1px solid var(--fs-panel-border, rgba(128,128,128,0.2)); border-radius: 0.65rem; overflow: hidden; background: var(--fs-panel-bg, rgba(128,128,128,0.04)); }
.at-cell { flex: 1 1 0; min-width: 7rem; display: flex; flex-direction: column; align-items: center; gap: 0.05rem; padding: 0.85rem 0.5rem; }
.at-cell + .at-cell { border-left: 1px solid var(--fs-forum-divider, rgba(128,128,128,0.14)); }
.at-cell b { font-size: 1.15rem; font-weight: 800; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.at-cell b a { color: var(--fs-panel-footer-accent, inherit); text-decoration: none; font-size: 0.92rem; }
.at-cell b a:hover { text-decoration: underline; }
.at-cell span { font-size: 0.58rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; opacity: 0.55; }
.at-cell--new { flex: 1.3 1 0; }
@media (max-width: 900px) {
.at-grid { grid-template-columns: 1fr; }
.at-cell { min-width: 33%; }
}
Template:
<div class="ch">
{{#each categories}}
<div class="ch-cat">
<div class="ch-spine">
<a href="{{ this.url }}">{{ this.name }}</a>
</div>
<div class="ch-list">
{{#each this.forums}}
<div class="ch-row{{#unless this.is_read}} ch-row--unread{{/unless}}">
<div class="ch-main">
<div class="ch-name">
<a href="{{ this.url }}">{{ this.name }}</a>
{{#unless this.is_read}}<span class="ch-flag">New</span>{{/unless}}
</div>
<div class="ch-desc">{{{ this.description }}}</div>
{{#if this.subforums}}
<div class="ch-subs">
{{#each this.subforums}}
<a href="{{ this.url }}" class="ch-sub{{#unless this.is_read}} ch-sub--unread{{/unless}}">{{ this.name }}</a>
{{/each}}
</div>
{{/if}}
{{#if this.last_post.author}}
<div class="ch-last">
<img src="{{ this.last_post.avatar_url }}" alt="{{ this.last_post.author }}" />
<a href="{{ this.last_post.url }}">{{ this.last_post.title | limit:44 }}</a>
<span class="ch-last-meta">{{ this.last_post.author }} · {{ this.last_post.date }}</span>
</div>
{{/if}}
</div>
<div class="ch-stats">
<span class="ch-stat"><b>{{ this.topics_count }}</b><span>topics</span></span>
<span class="ch-stat"><b>{{ this.replies_count }}</b><span>replies</span></span>
</div>
</div>
{{/each}}
</div>
</div>
{{/each}}
<div class="ch-foot">
<span class="ch-fstat"><b>{{ stats.topics }}</b> topics</span>
<span class="ch-fslash"></span>
<span class="ch-fstat"><b>{{ stats.replies }}</b> posts</span>
<span class="ch-fslash"></span>
<span class="ch-fstat"><b>{{ stats.members }}</b> members</span>
<span class="ch-fslash"></span>
<span class="ch-fstat"><b>{{ stats.online }}</b> online</span>
<span class="ch-fslash"></span>
<span class="ch-fstat">newest <a href="{{ stats.latest_member_url }}">{{ stats.latest_member }}</a></span>
</div>
</div>CSS:
.ch-cat { display: flex; gap: 1.2rem; counter-reset: chrow; }
.ch-cat + .ch-cat { margin-top: 2.4rem; }
.ch-spine { flex-shrink: 0; display: flex; justify-content: center; width: 2rem; border-right: 3px solid var(--fs-panel-footer-accent, rgba(128,128,128,0.5)); padding-right: 0.6rem; }
.ch-spine a { writing-mode: vertical-rl; transform: rotate(180deg); font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.28em; color: inherit; opacity: 0.55; text-decoration: none; white-space: nowrap; }
.ch-spine a:hover { opacity: 1; color: var(--fs-panel-footer-accent, inherit); }
.ch-list { flex: 1; min-width: 0; }
.ch-row { counter-increment: chrow; display: flex; align-items: flex-start; gap: 1.4rem; padding: 1.15rem 0.2rem; }
.ch-row::before { content: counter(chrow, decimal-leading-zero); font-size: 3rem; font-weight: 900; line-height: 1; letter-spacing: -0.04em; opacity: 0.14; font-variant-numeric: tabular-nums; flex-shrink: 0; min-width: 4.2rem; transition: opacity 0.15s ease, color 0.15s ease; }
.ch-row:hover::before { opacity: 0.85; color: var(--fs-panel-footer-accent, inherit); }
.ch-row--unread::before { opacity: 1; color: var(--fs-panel-footer-accent, inherit); }
.ch-row + .ch-row { border-top: 2px solid var(--fs-panel-border, rgba(128,128,128,0.2)); }
.ch-main { flex: 1; min-width: 0; }
.ch-name { display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap; }
.ch-name a { font-size: 1.18rem; font-weight: 800; letter-spacing: -0.02em; color: inherit; text-decoration: none; }
.ch-name a:hover { color: var(--fs-panel-footer-accent, inherit); }
.ch-row--unread .ch-name a { color: var(--fs-panel-footer-accent, inherit); }
.ch-flag { font-size: 0.56rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.12em; color: #fff; background: var(--fs-panel-footer-accent, #35a377); padding: 0.16rem 0.5rem; }
.ch-desc { font-size: 0.8rem; opacity: 0.62; line-height: 1.5; margin-top: 0.25rem; max-width: 36rem; }
.ch-desc p { margin: 0; }
.ch-subs { display: flex; flex-wrap: wrap; gap: 0.2rem 0.9rem; margin-top: 0.4rem; font-size: 0.73rem; }
.ch-sub { color: inherit; opacity: 0.65; text-decoration: none; }
.ch-sub:hover { opacity: 1; text-decoration: underline; }
.ch-sub--unread { opacity: 1; font-weight: 700; color: var(--fs-panel-footer-accent, inherit); }
.ch-last { display: flex; align-items: center; gap: 0.45rem; margin-top: 0.55rem; min-width: 0; font-size: 0.75rem; }
.ch-last img { flex-shrink: 0; width: 1.4rem; height: 1.4rem; border-radius: 50%; object-fit: cover; }
.ch-last a { font-weight: 600; color: inherit; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ch-last a:hover { text-decoration: underline; }
.ch-last-meta { flex-shrink: 0; opacity: 0.55; font-size: 0.68rem; }
.ch-stats { flex-shrink: 0; display: flex; gap: 1.4rem; padding-top: 0.35rem; }
.ch-stat { display: flex; flex-direction: column; align-items: flex-end; }
.ch-stat b { font-size: 1.05rem; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.ch-stat span { font-size: 0.58rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; opacity: 0.5; }
.ch-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 0.9rem; margin-top: 2.4rem; padding-top: 1rem; border-top: 3px solid var(--fs-panel-footer-accent, rgba(128,128,128,0.5)); font-size: 0.85rem; }
.ch-fstat b { font-size: 1.25rem; font-weight: 900; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.ch-fstat a { color: var(--fs-panel-footer-accent, inherit); font-weight: 800; text-decoration: none; }
.ch-fstat a:hover { text-decoration: underline; }
.ch-fslash { width: 2px; height: 1.3rem; background: var(--fs-panel-border, rgba(128,128,128,0.3)); transform: skewX(-18deg); }
@media (max-width: 768px) {
.ch-cat { gap: 0.7rem; }
.ch-spine { width: 1.4rem; padding-right: 0.4rem; }
.ch-row { gap: 0.8rem; }
.ch-row::before { font-size: 1.9rem; min-width: 2.6rem; }
.ch-stats { display: none; }
}More examples soon.
ForumSpark Support