UI

Layout classes shared by blocks and hero — theme, grid, align, layout, offset

Overview

Blocks and hero expose their layout options through a ui object in the front matter. hugolify-theme turns each value into a CSS class — it holds no style itself, so the class is only meaningful if the active styling module implements it.

The value is the class: theme: dark renders block-dark, grid: full renders block-full. A value the module does not style renders markup with no visual effect, never an error — which is why the tables below list the coverage of each module.

Blocks

ui object in a block’s front matter

blocks:
  - type: editorial
    ui:
      theme: dark    # block-dark
      grid: medium   # block-medium + col-medium on the row child
      offset: center # block-center + offset-center
      align: center  # block-align-center
      layout: carousel # block-carousel

The class string is built by func/GetBlockClasses.html , always prefixed with block-, alongside the block’s own type class (block-editorial).

Front matterClassDesign SystemBootstrap
themeblock-<value>accent black dark highlight light neutral white— only the legacy .block-bg (background: true)
alignblock-align-<value>start center end—
layoutblock-<value>carousel—
gridblock-<value>full (padding), width via col-*width via col-*
offsetblock-<value>position via offset-*position via offset-*

Available theme and grid values are declared per project in the admin config (params.admin.fields.theme.options and .grid.options, default light dark accent and container small medium large full). align and offset are always start, center or end.

Columns

grid and offset do not size the block themselves: func/GetColOffsetClass.html maps them to semantic column classes, implemented by both modules.

ClassSpanDesign SystemBootstrap
col-xsmall1/3✓✓
col-small1/2✓✓
col-medium2/3✓✓
col-large5/6✓✓
offset-centercentered✓✓
offset-endpushed right✓✓

The spans are relative to the active column count, not hardcoded to 12: @uncinq/css-base computes them from --columns, Bootstrap from $grid-columns via make-col().

Defaults per block

A ui value in the front matter belongs to that block alone. To give every block of a type the same look, declare it once outside the content: changing it later restyles the blocks already written, instead of leaving them behind.

Two places take that declaration, and they stack.

In the config — what the project ships

/config/_default/params.yaml

params:
  blocks:
    latest:
      ui:
        align: center
        grid: large
        layout: grid
        offset: center

This is the developer’s level. It travels with the repository and is not editable from the CMS, which is what you want for a decision the project should not drift away from.

In the data — what the CMS can retune

/data/blocks.yml holds the same thing in the same shape, and hugolify-admin exposes it as a Blocks file in the config collection. An integrator adjusts a block type there without touching the repository.

/data/blocks.yml

latest:
  ui:
    align: center
    grid: large
    layout: grid
    offset: center

The form lists every block type the project enables, one collapsible section each, selected-* variants included. A section arrives open when it already carries a value, so the screen says at a glance which of the types the site actually styles.

Values are read key by key, so a field left empty in the CMS falls back to the config rather than erasing it. A type can therefore be split between the two: the grid fixed in params.yaml, the theme left open to the CMS.

The file is not translated. How a block looks is not language content, so one /data/blocks.yml answers for every locale.

The ladder

func/GetBlockUI.html resolves four levels, from the weakest to the strongest:

  1. params.blocks.<type>.ui — the look the project ships
  2. data/blocks.yml → <type>.ui — the look the CMS sets, key by key
  3. the keys at the root of the block — the legacy v1 form
  4. the keys under the block’s own ui — they win even when empty, which is how one block opts out of a default

What an editor picks on a block itself lands in the fourth level, so it always wins over both defaults.

Every key of the table above is accepted. scrollsnap goes in either place too, in the same order, though it is resolved by SetScrollsnap rather than GetBlockUI and keeps a ladder of its own — see scrollsnap.

Calling a block template by hand

Each template names itself, so a partial rendering a block outside the blocks list of a page gets the defaults and the block-<type> class without passing anything. Pass type only to read the defaults of a more specific type, such as a selected-* variant rendered by selected.html.

{{ partial "blocks/templates/latest.html" (dict "section" "posts") }}
{{ partial "blocks/templates/selected.html" (dict "type" "selected-awards" "section" "awards") }}

A project template does the same, with its own type in both calls. The context is merged over it, so the type of the entry still wins when there is one:

{{- $ui := partial "func/GetBlockUI" (merge (dict "type" "title-xl") .) -}}
{{- $blockClass := partial "func/GetBlockClasses" (dict "type" "title-xl" "ui" $ui) -}}

Hero

hero object in a page’s front matter

hero:
  ui:
    align: center         # hero-center
    vertical_align: end   # hero-vertical-end
    theme: dark           # hero-dark
    darken: true          # hero-with-darken (darken under text only)
  image:
    src: '/images/cover.jpg'
    background: true      # hero-with-cover hero-with-cover-image (darken whole background)

Classes are built by commons/hero.html .

Front matterClassDesign SystemBootstrap
align: center / endhero-center hero-end✓✓
themehero-<value> — accent black dark highlight light neutral white✓✓
image / video + backgroundhero-with-cover + hero-with-cover-image / -video✓✓
image / video (side media)hero-with-image / hero-with-video✓✓
cover darkeninghero-cover-darken✓✓
vertical_alignhero-vertical-<value>✓—
darken: truehero-with-darken✓—

The hero themes are the one place where the two modules are explicitly kept in sync: _hero-theme.sass in hugolify-theme-bootstrap is a port of hero-theme.css from @uncinq/css-components, generated from the same seven names.

Adding a variant

A value with no CSS is inert, so a project-specific variant only needs a rule in the right layer — no template change:

/* assets/css/site.css — hugolify-theme-design-system */
@layer components {
  .block-brand {
    --block-color-background: var(--color-brand);
    --color-text: var(--color-text-on-brand);
  }
}

Then expose the value to the editors:

# /config/_default/params.yaml
admin:
  fields:
    theme:
      options: [light, dark, accent, brand]