Entry Listings
After creating an entry collection, you might want to customize how entries are displayed in the Sveltia CMS interface. The following options allow you to control various aspects of entry listings.
Summaries
By default, Sveltia CMS uses the title field (or a field defined with the identifier_field option) as the summary for each entry in the listing view. If the field is empty or missing, the title, name or label field is used instead, whichever has a value first.
Sometimes entries might only have a body field without a title field. In such cases, Sveltia CMS will look for a header in the Markdown body field, if it exists, or use the entry slug as a fallback to ensure that the summary is never empty. This behavior supports typical Markdown-based setups like VitePress and Docusaurus.
You can customize the summary displayed for each entry using the summary option. This option accepts a string with template tags that will be replaced with entry-specific values when generating the summary. For example, to display both the title and date of each entry in the summary, you can use the following configuration:
summary: '{{title}} ({{date}})'summary = "{{title}} ({{date}})"{
"summary": "{{title}} ({{date}})"
}{
summary: "{{title}} ({{date}})",
}Basic Markdown syntax is supported in the summary option, including bold, italics and inline code. For example:
summary: '**{{title}}** - _{{date}}_ `{{status}}`'summary = "**{{title}}** - _{{date}}_ `{{status}}`"{
"summary": "**{{title}}** - _{{date}}_ `{{status}}`"
}{
summary: "**{{title}}** - _{{date}}_ `{{status}}`",
}You can use string transformations with these template tags as well. For example:
summary: "{{title}} - {{date | date('DD MMM YYYY')}} {{published | ternary('', '(draft)')}}"summary = "{{title}} - {{date | date('DD MMM YYYY')}} {{published | ternary('', '(draft)')}}"{
"summary": "{{title}} - {{date | date('DD MMM YYYY')}} {{published | ternary('', '(draft)')}}"
}{
summary: "{{title}} - {{date | date('DD MMM YYYY')}} {{published | ternary('', '(draft)')}}",
}The following template tags are supported in the summary option, in addition to slug template tags except date-related ones:
{{dirname}}: The name of the directory containing the entry file, relative to the collectionfolder.{{filename}}: The entry file name without the extension.{{extension}}: The entry file extension.{{commit_author}}: The last commit author of the entry file from Git history (if available).{{commit_date}}: The last commit date of the entry file from Git history (if available).{{locales}}: The enabled locales for the entry when using i18n support.
Known issue
Git commit information is not available with the GitLab backend due to API limitations.
Thumbnails
By default, Sveltia CMS automatically looks for any non-nested, non-empty Image or File field in the entry to use as a thumbnail in the entry listing view. However, you can customize this behavior using the thumbnail option.
collections:
- name: posts
label: Blog Posts
folder: /content/posts
thumbnail: featuredImage
fields:
- { name: title, label: Title }
- { name: featuredImage, label: Featured Image, widget: image }
- { name: body, label: Body, widget: richtext }[[collections]]
name = "posts"
label = "Blog Posts"
folder = "/content/posts"
thumbnail = "featuredImage"
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "featuredImage"
label = "Featured Image"
widget = "image"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"{
"collections": [
{
"name": "posts",
"label": "Blog Posts",
"folder": "/content/posts",
"thumbnail": "featuredImage",
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "featuredImage", "label": "Featured Image", "widget": "image" },
{ "name": "body", "label": "Body", "widget": "richtext" }
]
}
]
}{
collections: [
{
name: "posts",
label: "Blog Posts",
folder: "/content/posts",
thumbnail: "featuredImage",
fields: [
{ name: "title", label: "Title" },
{ name: "featuredImage", label: "Featured Image", widget: "image" },
{ name: "body", label: "Body", widget: "richtext" },
],
},
],
}The thumbnail option can take a string or an array of strings representing the field names to be used as thumbnails. The first field that contains a valid image will be used as the thumbnail. For example:
thumbnail: [thumbnailImage, coverImage]thumbnail = ["thumbnailImage", "coverImage"]{
"thumbnail": ["thumbnailImage", "coverImage"]
}{
thumbnail: ["thumbnailImage", "coverImage"],
}A nested field can be specified using dot notation, e.g. heroImage.src. A wildcard in the field name is also supported, e.g. images.*.src, to target images in a list field.
Thumbnail Paths
If your thumbnails are stored at predictable locations rather than referenced by a field, you can specify a file path instead of a field name. A value starting with a slash is treated as a path, which is resolved in the same way as an Image field value, so it’s typically a path under your public_folder. This avoids adding an extra field to every entry just to hold a thumbnail path that can be derived from the entry itself.
The path can contain the same template tags as the preview_path option, including {{slug}}, {{dirname}}, {{filename}}, date and time tags, and field values. The date and time tags are based on the field specified with the preview_path_date_field option, or the first DateTime field in the collection. String transformations can be used as well. For example:
thumbnail: '/images/thumbnails/{{slug}}.webp'thumbnail = "/images/thumbnails/{{slug}}.webp"{
"thumbnail": "/images/thumbnails/{{slug}}.webp"
}{
thumbnail: "/images/thumbnails/{{slug}}.webp",
}Paths and field names can be combined in an array. They are tried in order, so the example below uses the coverImage field when no file exists at the given path:
thumbnail: ['/images/thumbnails/{{slug}}.webp', coverImage]thumbnail = ["/images/thumbnails/{{slug}}.webp", "coverImage"]{
"thumbnail": ["/images/thumbnails/{{slug}}.webp", "coverImage"]
}{
thumbnail: ["/images/thumbnails/{{slug}}.webp", "coverImage"],
}The template tags are filled with the values of the default locale. If a tag cannot be resolved, for example because the field it refers to is empty, the path is skipped and the next candidate is tried. A relative path is not supported, because a value without a leading slash is treated as a field name.
Disabling Thumbnails
Occasionally, you may not have suitable images for thumbnails. For example, your images may have subtle differences or varied aspect ratios. In that case, you can disable the thumbnail feature by setting the thumbnail option to false or an empty array:
thumbnail: falsethumbnail = false{
"thumbnail": false
}{
thumbnail: false,
}Including and Excluding Entries
Sometimes, you may want to include or exclude specific entries from being displayed in the Sveltia CMS interface. Sveltia CMS provides options to manage this.
Managing Hugo’s Special Index File
By default, Hugo’s special _index.md file are hidden in a folder collection unless the path option is configured to end with _index and the extension is set to md. You have to create a file collection to manage the file, since it usually comes with a different set of fields than regular entry fields.
The index_file option allows you to include and manage the special index file within the same folder collection. This way, editors can easily access and edit the index file alongside regular entries.
collections:
- name: posts
label: Blog posts
folder: /content/posts
fields: # Fields for regular entries
- { name: title, label: Title }
- { name: date, label: Published Date, widget: datetime }
- { name: description, label: Description }
- { name: body, label: Body, widget: richtext }
index_file:
fields: # Fields for the index file
- { name: title, label: Title }
- { name: body, label: Body, widget: richtext }[[collections]]
name = "posts"
label = "Blog posts"
folder = "/content/posts"
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "date"
label = "Published Date"
widget = "datetime"
[[collections.fields]]
name = "description"
label = "Description"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"
[collections.index_file]
[[collections.index_file.fields]]
name = "title"
label = "Title"
[[collections.index_file.fields]]
name = "body"
label = "Body"
widget = "richtext"{
"collections": [
{
"name": "posts",
"label": "Blog posts",
"folder": "/content/posts",
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "date", "label": "Published Date", "widget": "datetime" },
{ "name": "description", "label": "Description" },
{ "name": "body", "label": "Body", "widget": "richtext" }
],
"index_file": {
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "body", "label": "Body", "widget": "richtext" }
]
}
}
]
}{
collections: [
{
name: "posts",
label: "Blog posts",
folder: "/content/posts",
fields: [
{ name: "title", label: "Title" },
{ name: "date", label: "Published Date", widget: "datetime" },
{ name: "description", label: "Description" },
{ name: "body", label: "Body", widget: "richtext" },
],
index_file: {
fields: [
{ name: "title", label: "Title" },
{ name: "body", label: "Body", widget: "richtext" },
],
},
},
],
}Here is an example of full customization. All options are optional.
index_file:
name: _index # File name without a locale or extension. Default: _index
extension: md # File extension. Default: the collection’s extension
format: frontmatter # File format. Default: detected from the extension, or the collection’s format
label: Index File # Human-readable file label. Default: Index File
icon: home # Material Symbols icon name. Default: home
fields: # Fields for the index file. If omitted, regular entry fields are used
...
editor:
preview: false # Hide the preview pane if needed. Default: true[index_file]
name = "_index"
extension = "md"
format = "frontmatter"
label = "Index File"
icon = "home"
# fields would be defined as [[index_file.fields]] elements
# editor configuration
[index_file.editor]
preview = false{
"index_file": {
"name": "_index",
"extension": "md",
"format": "frontmatter",
"label": "Index File",
"icon": "home",
"fields": [],
"editor": {
"preview": false
}
}
}{
index_file: {
name: "_index",
extension: "md",
format: "frontmatter",
label: "Index File",
icon: "home",
fields: [],
editor: {
preview: false,
},
},
}If your regular entry fields and index file fields are identical and you don’t need any options, simply write:
index_file: trueindex_file = true{
"index_file": true
}{
index_file: true,
}Note that the special index file is placed right under the folder, regardless of the collection’s path option. For example, if the path is {{year}}/{{slug}}, a regular entry would be saved as content/posts/2025/title.md, but the index file remains at content/posts/_index.md.
For a multilingual Hugo site using translation by content directory, where the section folders sit below the locale folders, put the {{locale}} placeholder in the folder option, e.g. content/{{locale}}/posts. The index file then lands in each locale’s section folder, e.g. content/en/posts/_index.md, rather than under the content folder.
The index file is listed beside the regular entries, but it isn’t counted as one of them, because it stands for the collection’s own page rather than for something in it. It’s left out of the entry count shown next to the collection in the collection list, and it doesn’t take up a slot in the collection’s limit. A collection holding nothing but its index file therefore shows a count of 0.
Only the collection’s own index file is treated this way. When one collection’s folder contains another’s — a pages collection on content with a posts collection on content/posts, say — the inner collection’s content/posts/_index.md is an ordinary entry as far as the outer collection is concerned: the outer collection’s filter applies to it, and it’s counted like any other entry the filter lets through.
Managing Eleventy’s Directory Data File
The index file doesn’t have to be a Hugo _index.md: any file with a fixed name right under the collection folder can be one, in a format of its own. Eleventy’s directory data file, for example, is a JSON (or YAML, if configured) file named after the folder, like posts/posts.json, that holds the data every Markdown entry in the folder inherits. Set the name and extension (or format) options to manage it beside the entries:
collections:
- name: posts
label: Blog posts
folder: content/posts
fields:
- { name: title, label: Title }
- { name: body, label: Body, widget: richtext }
index_file:
name: posts
extension: json
label: Posts Data
icon: description
fields:
- { name: layout, label: Layout }
- { name: tags, label: Tags, widget: list }[[collections]]
name = "posts"
label = "Blog posts"
folder = "content/posts"
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"
[collections.index_file]
name = "posts"
extension = "json"
label = "Posts Data"
icon = "description"
[[collections.index_file.fields]]
name = "layout"
label = "Layout"
[[collections.index_file.fields]]
name = "tags"
label = "Tags"
widget = "list"{
"collections": [
{
"name": "posts",
"label": "Blog posts",
"folder": "content/posts",
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "body", "label": "Body", "widget": "richtext" }
],
"index_file": {
"name": "posts",
"extension": "json",
"label": "Posts Data",
"icon": "description",
"fields": [
{ "name": "layout", "label": "Layout" },
{ "name": "tags", "label": "Tags", "widget": "list" }
]
}
}
]
}{
collections: [
{
name: "posts",
label: "Blog posts",
folder: "content/posts",
fields: [
{ name: "title", label: "Title" },
{ name: "body", label: "Body", widget: "richtext" },
],
index_file: {
name: "posts",
extension: "json",
label: "Posts Data",
icon: "description",
fields: [
{ name: "layout", label: "Layout" },
{ name: "tags", label: "Tags", widget: "list" },
],
},
},
],
}With this configuration, content/posts/posts.json is listed and edited as the collection’s index file, read and written as JSON, while content/posts/*.md are the regular entries. Other .json files in the folder are left alone. The format option works as it does for the collection: give it alone to have the extension follow, or give both when they don’t go together, e.g. extension: md with format: toml-frontmatter. The front matter delimiters, body field and other file options are shared with the entries.
Reserved Name
An index file with an extension of its own could sit beside an entry of the same name, like posts/posts.md next to posts/posts.json, but the two would be addressed the same way in the CMS. The index file’s name is therefore reserved: such an entry is left out of the collection, and a new entry whose slug would clash with it is renamed like any duplicate.
Filtering Entries
With the filter option, you can limit the entries displayed in the Sveltia CMS interface based on specific criteria. This is useful for collections where you want to show only a subset of entries, such as a specific language or category.
This option takes an object with two properties:
field: The name of the field to filter by.valueorpattern: The value that the field must match for an entry to be included.- The
valueproperty checks for exact matches, while thepatternproperty allows for regular expression matching. - The
valuecan be a single value or an array of values. If an array is provided, entries matching any of the values will be included. Ifnullis provided as a value, entries where the field is not set will be included. - The
patternproperty should be a string representing a valid regular expression.
- The
The example below shows how to create two separate collections for English and French blog posts, filtering entries based on the lang field:
collections:
- name: english-posts
label: English Posts
folder: /content/posts
filter: { field: lang, value: en }
fields:
- { name: lang, label: Language, widget: select, options: [en, fr] }
- { name: title, label: Title }
- { name: body, label: Body, widget: richtext }
- name: french-posts
label: French Posts
folder: /content/posts
filter: { field: lang, value: fr }
fields:
- { name: lang, label: Language, widget: select, options: [en, fr] }
- { name: title, label: Title }
- { name: body, label: Body, widget: richtext }[[collections]]
name = "english-posts"
label = "English Posts"
folder = "/content/posts"
filter = { field = "lang", value = "en" }
[[collections.fields]]
name = "lang"
label = "Language"
widget = "select"
options = ["en", "fr"]
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"
[[collections]]
name = "french-posts"
label = "French Posts"
folder = "/content/posts"
filter = { field = "lang", value = "fr" }
[[collections.fields]]
name = "lang"
label = "Language"
widget = "select"
options = ["en", "fr"]
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"{
"collections": [
{
"name": "english-posts",
"label": "English Posts",
"folder": "/content/posts",
"filter": { "field": "lang", "value": "en" },
"fields": [
{ "name": "lang", "label": "Language", "widget": "select", "options": ["en", "fr"] },
{ "name": "title", "label": "Title" },
{ "name": "body", "label": "Body", "widget": "richtext" }
]
},
{
"name": "french-posts",
"label": "French Posts",
"folder": "/content/posts",
"filter": { "field": "lang", "value": "fr" },
"fields": [
{ "name": "lang", "label": "Language", "widget": "select", "options": ["en", "fr"] },
{ "name": "title", "label": "Title" },
{ "name": "body", "label": "Body", "widget": "richtext" }
]
}
]
}{
collections: [
{
name: "english-posts",
label: "English Posts",
folder: "/content/posts",
filter: { field: "lang", value: "en" },
fields: [
{ name: "lang", label: "Language", widget: "select", options: ["en", "fr"] },
{ name: "title", label: "Title" },
{ name: "body", label: "Body", widget: "richtext" },
],
},
{
name: "french-posts",
label: "French Posts",
folder: "/content/posts",
filter: { field: "lang", value: "fr" },
fields: [
{ name: "lang", label: "Language", widget: "select", options: ["en", "fr"] },
{ name: "title", label: "Title" },
{ name: "body", label: "Body", widget: "richtext" },
],
},
],
}