Grav Theme Configuration — Blueprints, Form Fields and Theme Settings
In this tutorial, you'll learn Grav theme configuration — creating blueprints.yaml and theme.yaml files, defining form fields for the Admin panel, exposing configurable theme options, and building a settings page for your theme.
What You'll Learn
- The role of
blueprints.yamlin theme configuration - Defining form fields for Admin panel settings
- The
theme.yamlfile for default theme values - Accessing theme configuration in templates
- Creating custom theme options (colors, layouts, social links)
- Best practices for theme configuration structure
Why It Matters
In WordPress, theme options are typically built with the Customizer API or option pages. In Grav, theme configuration is YAML-based. A blueprints.yaml file defines what settings appear in the Admin panel. A theme.yaml file stores default values. Twig templates access these values through config.themes.THEMENAME. This approach is simpler, file-based, and Git-friendly — no database storage, no admin interface code, just structured YAML.
Real-World Use
A design agency builds a customizable Grav theme for clients. The theme has options for: primary color, font family, layout (sidebar left, sidebar right, full width), social media links, footer content, and logo upload. Each option is defined in blueprints.yaml. Clients change settings through the Admin panel, and the changes are stored in theme.yaml. Templates use config.themes.mytheme.primary_color to apply the selected color. No PHP code needed for any of this.
Learning Path
flowchart LR
A["Custom Twig Extensions"] --> B["Theme Configuration
← You are here"]:::current
B --> C["Theme Assets"]
C --> D["Theme Inheritance"]
D --> E["Theme Languages"]
E --> F["Plugin Architecture"]
classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px
theme.yaml — Default Values
Every theme should have a theme.yaml file that defines default configuration values:
user/themes/mytheme/theme.yaml:
# General
enabled: true
color_scheme: light
# Layout
layout:
sidebar_position: right
sidebar_width: 300
container_width: 1200
# Colors
colors:
primary: '#3498db'
secondary: '#2ecc71'
background: '#ffffff'
text: '#333333'
link: '#2980b9'
# Typography
fonts:
heading: 'Inter'
body: 'Inter'
# Social
social:
twitter: 'https://twitter.com/dodatech'
github: 'https://github.com/dodatech'
linkedin: ''
# Footer
footer:
copyright: 'Built by DodaTech'
show_social: true
blueprints.yaml — Admin Form Fields
The blueprints.yaml file defines the form fields that appear in the Admin panel when editing the theme:
user/themes/mytheme/blueprints.yaml:
name: My Theme
version: 1.0.0
description: A customizable theme for documentation sites
icon: paint-brush
author:
name: DodaTech
email: support@dodatech.com
homepage: https://dodatech.com
keywords: grav, theme, documentation
form:
validation: loose
fields:
enabled:
type: toggle
label: Theme enabled
highlight: 1
default: 1
options:
1: Enabled
0: Disabled
validate:
type: bool
color_scheme:
type: select
label: Color scheme
default: light
options:
light: Light
dark: Dark
auto: Auto (follows system)
layout.sidebar_position:
type: select
label: Sidebar position
default: right
options:
left: Left
right: Right
none: No sidebar
layout.sidebar_width:
type: range
label: Sidebar width (px)
default: 300
validate:
min: 200
max: 400
step: 10
layout.container_width:
type: range
label: Container width (px)
default: 1200
validate:
min: 800
max: 1600
step: 50
colors.primary:
type: colorpicker
label: Primary color
default: '#3498db'
colors.secondary:
type: colorpicker
label: Secondary color
default: '#2ecc71'
colors.background:
type: colorpicker
label: Background color
default: '#ffffff'
colors.text:
type: colorpicker
label: Text color
default: '#333333'
colors.link:
type: colorpicker
label: Link color
default: '#2980b9'
fonts.heading:
type: select
label: Heading font
default: Inter
options:
Inter: Inter
Roboto: Roboto
'Open Sans': Open Sans
Lato: Lato
'Source Sans Pro': Source Sans Pro
fonts.body:
type: select
label: Body font
default: Inter
options:
Inter: Inter
Roboto: Roboto
'Open Sans': Open Sans
Lato: Lato
'Source Sans Pro': Source Sans Pro
social.twitter:
type: text
label: Twitter URL
size: large
social.github:
type: text
label: GitHub URL
size: large
social.linkedin:
type: text
label: LinkedIn URL
size: large
footer.copyright:
type: text
label: Copyright text
size: large
footer.show_social:
type: toggle
label: Show social links in footer
default: 1
options:
1: Yes
0: No
Form Field Types
Grav Admin supports many form field types:
| Type | Use | Example |
|---|---|---|
text |
Single line text | Site title |
textarea |
Multi-line text | Footer content |
select |
Dropdown selection | Layout choice |
toggle |
On/off switch | Enable feature |
range |
Slider | Width, count |
colorpicker |
Color selector | Primary color |
file |
File upload | Logo image |
editor |
Rich text editor | Custom CSS |
hidden |
Invisible field | Version tracking |
section |
Visual section separator | Grouping fields |
Nested Field Names
Use dot notation for nested configuration values:
colors.primary:
type: colorpicker
label: Primary color
layout.sidebar.position:
type: select
label: Sidebar position
social.links.twitter:
type: text
label: Twitter URL
These map to config.themes.mytheme.colors.primary, config.themes.mytheme.layout.sidebar.position, etc.
Accessing Theme Config in Templates
{# Get theme configuration values #}
{% set primary = config.themes.mytheme.colors.primary %}
{% set sidebar_pos = config.themes.mytheme.layout.sidebar_position %}
{% set container_width = config.themes.mytheme.layout.container_width %}
{# Use in template #}
<style>
:root {
--primary: {{ primary }};
--secondary: {{ config.themes.mytheme.colors.secondary }};
--background: {{ config.themes.mytheme.colors.background }};
--text: {{ config.themes.mytheme.colors.text }};
}
</style>
<div class="container" style="max-width: {{ container_width }}px">
<main class="content">
{{ page.content|raw }}
</main>
{% if sidebar_pos != 'none' %}
<aside class="sidebar sidebar-{{ sidebar_pos }}"
style="width: {{ config.themes.mytheme.layout.sidebar_width }}px">
{% include 'partials/sidebar.html.twig' %}
</aside>
{% endif %}
</div>
Fallback Values
Always provide fallbacks in case the config value is not set:
{% set primary = config.themes.mytheme.colors.primary|default('#3498db') %}
{% set show_social = config.themes.mytheme.footer.show_social|default(true) %}
Dynamic CSS with Theme Config
Inject theme colors as CSS custom properties:
{% do assets.addInlineCss("
:root {
--color-primary: #{config.themes.mytheme.colors.primary|default('#3498db')};
--color-secondary: #{config.themes.mytheme.colors.secondary|default('#2ecc71')};
--color-background: #{config.themes.mytheme.colors.background|default('#ffffff')};
--color-text: #{config.themes.mytheme.colors.text|default('#333333')};
--color-link: #{config.themes.mytheme.colors.link|default('#2980b9')};
--font-heading: '#{config.themes.mytheme.fonts.heading|default('Inter')}';
--font-body: '#{config.themes.mytheme.fonts.body|default('Inter')}';
}
") %}
Validation Rules
Add validation to prevent incorrect values:
layout.sidebar_width:
type: range
label: Sidebar width (px)
default: 300
validate:
min: 200
max: 400
step: 10
required: true
footer.copyright:
type: text
label: Copyright text
validate:
maxlength: 200
Theme Configuration File Location
After saving settings in the Admin panel, Grav stores the values in:
user/config/themes/mytheme.yaml
This file overrides the defaults in theme.yaml. Both files are readable in templates through the same config path.
Learning Path
flowchart LR
A["Custom Twig Extensions"] --> B["Theme Configuration
← You are here"]:::current
B --> C["Theme Assets"]
C --> D["Theme Inheritance"]
D --> E["Theme Languages"]
classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px
Common Mistakes
Not creating
blueprints.yaml: Without blueprints.yaml, the Admin panel shows no settings for your theme. Users cannot customize the theme through the admin interface.Mismatched field names: The field names in blueprints.yaml must match the configuration keys in theme.yaml. A field named
colors.primarymaps toconfig.themes.mytheme.colors.primary.Forgetting to provide defaults in templates: If a theme option is not set,
config.themes.mytheme.someOptionreturns null. Always use|default(value)in templates.Using unsupported field types: Not all form field types are available. Check the Admin plugin documentation for supported types. Using an unsupported type causes the field to not render.
Overwriting
user/config/themes/mytheme.yaml: This file is user-specific configuration. In a Git workflow, committheme.yaml(defaults) but adduser/config/themes/mytheme.yamlto.gitignore.
Practice Questions
What is the purpose of
blueprints.yamlin a theme? Answer: It defines the form fields that appear in the Admin panel when editing theme settings. Each field maps to a configuration value accessible in templates.How do you access a theme configuration value in a Twig template? Answer: Use
config.themes.THEMENAME.PATH. For example,config.themes.mytheme.colors.primaryaccesses the primary color setting.What happens when a user saves theme settings in the Admin panel? Answer: Grav writes the values to
user/config/themes/mytheme.yaml. These values override the defaults intheme.yamlbut are accessed through the same config path.How do you provide a fallback for a config value in a template? Answer: Use the
|default()filter:{% set primary = config.themes.mytheme.colors.primary|default('#3498db') %}.Challenge: Build a complete theme configuration for a portfolio site. Create blueprints.yaml with sections for: general settings (logo upload, favicon, enable dark mode), layout settings (grid columns: 2/3/4, container width, show sidebar), colors (primary, secondary, accent, background, text, card background), typography (heading font, body font, base font size, line height), hero section (enable hero, headline, subtitle, background image, CTA text and URL), social links (Twitter, GitHub, LinkedIn, Dribbble, YouTube), footer (copyright text, show social, columns: 1/2/3/4), and custom code (header JS, footer JS, custom CSS). Create theme.yaml with sensible defaults and access all values in templates with fallbacks.
FAQ
Mini Project
Goal: Create a fully configurable Grav theme with 20+ options.
- Create
theme.yamlwith default configuration values - Create
blueprints.yamlwith form fields organized in sections - Include at least 6 different field types (text, select, toggle, colorpicker, range, file)
- Create a Twig template that reads theme config and applies it dynamically
- Generate CSS custom properties from theme colors
- Add layout options that change template structure (sidebar, columns, width)
- Add social links that render conditionally
- Add a logo upload field with fallback to text logo
- Add a custom code section (header/footer JS and CSS)
- Test that all settings render correctly and save properly
What's Next
Now your theme is configurable. Next, learn asset management:
Continue to Lesson 21: Theme Assets — CSS/JS pipeline, asset merging, Minification, and loading strategies.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro