Entry Views
Sveltia CMS provides several options to customize how entries are displayed in the listing view. Users can sort, group and filter entries based on specific fields to improve navigation and organization.
Table View
The entry list can be shown in three views: a table, a list and a grid of thumbnails.
- The table view shows a column for each piece of information that tells the entries apart, such as the date, the author and the category.
- The list view only shows the entry summary.
- The grid view is only available when the entries have thumbnails.
The table view is the default, until a user picks another view with the buttons in the toolbar. A collection opened before the table view was introduced keeps the view it was shown in then, usually the list view, until the user picks the table.
The table view is shown on a large screen, where the columns fit. On a smaller screen, the list view is shown instead. In reorder mode, the entries are always shown in a list.
The table is read-only: click a row to open the entry, as in the list view. To change the values of many entries at once, use bulk editing.
Choosing Columns
By default, the table shows the entry summary, followed by a column for each field the entries can be sorted by, as they are the fields that tell the entries apart. The identifier field, usually title, is left out, as the summary already shows it.
You can choose the columns with the table_columns option instead. It accepts a list of field names, which can include:
- nested fields in dot notation like
author.name - the special key
_summaryfor the entry summary - the special keys
slug,commit_dateandcommit_author
To give a column a header other than the field’s label, use an object with the field and label properties:
collections:
- name: posts
label: Blog posts
folder: /content/posts
fields:
- { name: title, label: Title }
- { name: date, label: Published Date, widget: datetime }
- { name: author, label: Author, widget: object, fields: [{ name: name, label: Name }] }
- { name: draft, label: Draft, widget: boolean }
- { name: body, label: Body, widget: richtext }
table_columns:
- title
- date
- { field: author.name, label: Author }
- draft[[collections]]
name = "posts"
label = "Blog posts"
folder = "/content/posts"
table_columns = [
"title",
"date",
{ field = "author.name", label = "Author" },
"draft",
]
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "date"
label = "Published Date"
widget = "datetime"
[[collections.fields]]
name = "author"
label = "Author"
widget = "object"
fields = [{ name = "name", label = "Name" }]
[[collections.fields]]
name = "draft"
label = "Draft"
widget = "boolean"
[[collections.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": "author", "label": "Author", "widget": "object", "fields": [{ "name": "name", "label": "Name" }] },
{ "name": "draft", "label": "Draft", "widget": "boolean" },
{ "name": "body", "label": "Body", "widget": "richtext" }
],
"table_columns": [
"title",
"date",
{ "field": "author.name", "label": "Author" },
"draft"
]
}
]
}{
collections: [
{
name: "posts",
label: "Blog posts",
folder: "/content/posts",
fields: [
{ name: "title", label: "Title" },
{ name: "date", label: "Published Date", widget: "datetime" },
{ name: "author", label: "Author", widget: "object", fields: [{ name: "name", label: "Name" }] },
{ name: "draft", label: "Draft", widget: "boolean" },
{ name: "body", label: "Body", widget: "richtext" },
],
table_columns: [
"title",
"date",
{ field: "author.name", label: "Author" },
"draft",
],
},
],
}A column can also show a template, written the same way as the summary option, with the same tags and transformations. This lets the table show entry metadata such as {{locales}} for the enabled locales, {{dirname}}, {{filename}} and {{extension}}, or combine several values in one column:
table_columns:
- title
- '{{locales}}'
- { field: '{{filename}}.{{extension}}', label: File }
- { field: "{{date | date('YYYY-MM-DD')}}", label: Published }A template made of a single tag, such as {{locales}} or {{commit_date}}, gets a header named after it, and its column can be sorted if the tag is one of the sortable fields. Give a longer template a label, or its header shows the template itself.
Each cell shows the field’s value the way a summary template would:
- a date in the user’s format
- a Select field’s option by its label
- a Relation field’s referenced entry by its display value
- a list as comma-separated values
- a rich text field without its formatting
A Boolean field is shown as a check mark when it’s on. With i18n enabled, the values are taken from the default locale. If a listed field isn’t defined in the collection, Sveltia CMS raises a configuration error on startup.
A column whose field is also one of the sortable fields has a clickable header that sorts the entries by it, the same way the Sort menu does; click it again to reverse the order.
Static CMS compatibility
The summary_fields option of Static CMS, a list of field names where summary stands for the entry summary, is supported as an alias of table_columns. It’s ignored if table_columns is also defined.
Sorting
By default, Sveltia CMS supports sorting by title, name, date, author and description fields if they exist in the collection, as well as by the identifier field if it’s set with the identifier_field option. If the date and author fields are not present, Sveltia CMS will look for commit date and author information from Git history (if available) to enable sorting by those fields.
When the summary option is defined for a collection, Sveltia CMS also enables sorting by entry summaries. This allows you to sort entries based on the customized summary content, which can include multiple fields and string transformations.
When the reorder option is enabled for a collection, Sveltia CMS enables manual sorting of entries in the listing view. This allows users to drag and drop entries to reorder them as needed.
You can customize the sortable fields using the sortable_fields option. It accepts an array of field names that you want to enable for sorting in the entry listing view. It also accepts the following special keys, which read entry metadata instead of a field:
slug: Sort entries by their slugs.commit_date: Sort entries by the date of the last commit that modified the entry file.commit_author: Sort entries by the author of the last commit that modified the entry file.
The commit_date and commit_author keys are only shown when Git commit information is available for the collection’s entries; otherwise, they are ignored. Even with sortable_fields defined, Sveltia CMS adds them automatically when the information is available and the list doesn’t include date or author, respectively.
Entries without a value for the sort field, such as an empty date, are always listed last, whether the order is ascending or descending and whatever the field type.
The example below shows how to enable sorting by custom fields such as category and nested fields like author.name:
collections:
- name: posts
label: Blog posts
folder: /content/posts
fields:
- { name: title, label: Title }
- { name: published_date, label: Published Date, widget: datetime }
- {
name: author,
label: Author,
widget: object,
fields: [{ name: name, label: Name }, { name: email, label: Email }],
}
- { name: category, label: Category }
- { name: body, label: Body, widget: richtext }
sortable_fields: [title, published_date, author.name, category][[collections]]
name = "posts"
label = "Blog posts"
folder = "/content/posts"
sortable_fields = ["title", "published_date", "author.name", "category"]
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "published_date"
label = "Published Date"
widget = "datetime"
[[collections.fields]]
name = "author"
label = "Author"
widget = "object"
[[collections.fields.fields]]
name = "name"
label = "Name"
[[collections.fields.fields]]
name = "email"
label = "Email"
[[collections.fields]]
name = "category"
label = "Category"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"{
"collections": [
{
"name": "posts",
"label": "Blog posts",
"folder": "/content/posts",
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "published_date", "label": "Published Date", "widget": "datetime" },
{
"name": "author",
"label": "Author",
"widget": "object",
"fields": [
{ "name": "name", "label": "Name" },
{ "name": "email", "label": "Email" }
]
},
{ "name": "category", "label": "Category" },
{ "name": "body", "label": "Body", "widget": "richtext" }
],
"sortable_fields": ["title", "published_date", "author.name", "category"]
}
]
}{
collections: [
{
name: "posts",
label: "Blog posts",
folder: "/content/posts",
fields: [
{ name: "title", label: "Title" },
{ name: "published_date", label: "Published Date", widget: "datetime" },
{ name: "author", label: "Author", widget: "object", fields: [
{ name: "name", label: "Name" },
{ name: "email", label: "Email" },
] },
{ name: "category", label: "Category" },
{ name: "body", label: "Body", widget: "richtext" },
],
sortable_fields: ["title", "published_date", "author.name", "category"],
},
],
}Each item in the sortable_fields list can also be an object with the following options, as in Decap CMS. Objects and field names can be mixed in the same list.
field: The field name or special key to sort by. Required.label: The text shown in the Sort menu. Defaults to the field’s label.default_sort: Makes the field the default sort key. Useascortruefor ascending order, ordescfor descending order.
The example below sorts the entries by published_date in descending order by default, and shows the field as “Publish date” in the Sort menu:
sortable_fields:
- title
- { field: published_date, label: Publish date, default_sort: desc }
- author.name
- categoryOnly one item can have the default_sort option. Giving it to more than one item is reported as a config validation error on the login screen. The default sort applies until the user picks another sort key or order in the Sort menu, which Sveltia CMS remembers for the collection.
Extended syntax
Sveltia CMS supports an extended syntax used in Static CMS to define a default sort field and direction. This is useful if you want entries to be sorted by a date field in descending order by default. Here is the same default sort using the extended syntax:
sortable_fields:
fields: [title, published_date, author.name, category]
default:
field: published_date
direction: descendingThe default direction is ascending if not specified.
For backward compatibility with Static CMS, the direction option accepts title case values: Ascending and Descending. However, None is not supported and has the same effect as ascending.
Known issue
Git commit information is currently loaded only with the GitHub backend. With the GitLab and Gitea/Forgejo backends, it’s only available for entries saved during the current session, due to API limitations. It’s not available in the local workflow or with the Test backend.
Grouping
The view_groups option allows you to group entries in the listing view based on specific field values. This is useful for organizing entries into categories or sections for easier navigation.
The example below demonstrates how to group blog posts by their draft status and by the year extracted from the date field:
collections:
- name: posts
label: Blog posts
folder: /content/posts
fields:
- { name: title, label: Title }
- { name: date, label: Published Date, widget: datetime }
- { name: draft, label: Draft, widget: boolean }
- { name: body, label: Body, widget: richtext }
view_groups:
- label: Drafts
field: draft
- label: Year
field: date
pattern: '\d{4}'[[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 = "draft"
label = "Draft"
widget = "boolean"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"
[[collections.view_groups]]
label = "Drafts"
field = "draft"
[[collections.view_groups]]
label = "Year"
field = "date"
pattern = "\\d{4}"{
"collections": [
{
"name": "posts",
"label": "Blog posts",
"folder": "/content/posts",
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "date", "label": "Published Date", "widget": "datetime" },
{ "name": "draft", "label": "Draft", "widget": "boolean" },
{ "name": "body", "label": "Body", "widget": "richtext" }
],
"view_groups": [
{
"label": "Drafts",
"field": "draft"
},
{
"label": "Year",
"field": "date",
"pattern": "\\d{4}"
}
]
}
]
}{
collections: [
{
name: "posts",
label: "Blog posts",
folder: "/content/posts",
fields: [
{ name: "title", label: "Title" },
{ name: "date", label: "Published Date", widget: "datetime" },
{ name: "draft", label: "Draft", widget: "boolean" },
{ name: "body", label: "Body", widget: "richtext" },
],
view_groups: [
{
label: "Drafts",
field: "draft",
},
{
label: "Year",
field: "date",
pattern: "\\d{4}",
},
],
},
],
}Without a pattern or a comparison option, entries are grouped by the field value itself, as with the draft group above. With a pattern, they are grouped by the part of the field value that matches it, such as the four-digit year of the date field.
Extended syntax
Sveltia CMS supports an extended syntax used in Static CMS to define a default group. Here is the same configuration using the extended syntax:
view_groups:
groups:
- name: drafts
label: Drafts
field: draft
- name: year
label: Year
field: date
pattern: '\d{4}'
default: yearIn this syntax, each group needs a name, so that the default option can refer to it. The default option has to be the name of one of the groups. Any other name is reported as a config validation error on the login screen, because the collection would otherwise open ungrouped.
To sort the Year group in descending order by date, you can add the sortable_fields property as described in the Sorting section above:
sortable_fields:
fields: [date, title]
default:
field: date
direction: descendingA named view group can also be used with the reorder option to let editors reorder entries within their own group.
Grouping by a Comparison
A view group can also split the entries by a comparison, using the same options as a view filter. The entries satisfying the condition are grouped under the group’s label, and the other entries under “Other”. For example, the following group lists the upcoming events first, followed by the past and undated ones:
view_groups:
- label: Upcoming
field: date
gte: '{{today}}'Filtering
The view_filters option allows you to define preset filters that editors can quickly apply to the entry listing view. This is useful for quickly accessing specific subsets of entries based on common criteria.
collections:
- name: posts
label: Blog posts
folder: /content/posts
fields:
- { name: title, label: Title }
- { name: date, label: Published Date, widget: datetime }
- { name: draft, label: Draft, widget: boolean }
- { name: category, label: Category }
- { name: body, label: Body, widget: richtext }
view_filters:
- label: Drafts
field: draft
pattern: true
- label: Posts from 2024
field: date
pattern: '^2024'
- label: Travel or Food
field: category
pattern: travel|food[[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 = "draft"
label = "Draft"
widget = "boolean"
[[collections.fields]]
name = "category"
label = "Category"
[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"
[[collections.view_filters]]
label = "Drafts"
field = "draft"
pattern = "true"
[[collections.view_filters]]
label = "Posts from 2024"
field = "date"
pattern = "^2024"
[[collections.view_filters]]
label = "Travel or Food"
field = "category"
pattern = "travel|food"{
"collections": [
{
"name": "posts",
"label": "Blog posts",
"folder": "/content/posts",
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "date", "label": "Published Date", "widget": "datetime" },
{ "name": "draft", "label": "Draft", "widget": "boolean" },
{ "name": "category", "label": "Category" },
{ "name": "body", "label": "Body", "widget": "richtext" }
],
"view_filters": [
{
"label": "Drafts",
"field": "draft",
"pattern": "true"
},
{
"label": "Posts from 2024",
"field": "date",
"pattern": "^2024"
},
{
"label": "Travel or Food",
"field": "category",
"pattern": "travel|food"
}
]
}
]
}{
collections: [
{
name: "posts",
label: "Blog posts",
folder: "/content/posts",
fields: [
{ name: "title", label: "Title" },
{ name: "date", label: "Published Date", widget: "datetime" },
{ name: "draft", label: "Draft", widget: "boolean" },
{ name: "category", label: "Category" },
{ name: "body", label: "Body", widget: "richtext" },
],
view_filters: [
{
label: "Drafts",
field: "draft",
pattern: "true",
},
{
label: "Posts from 2024",
field: "date",
pattern: "^2024",
},
{
label: "Travel or Food",
field: "category",
pattern: "travel|food",
},
],
},
],
}Extended syntax
Sveltia CMS supports an extended syntax used in Static CMS to define a default filter. Here is the same configuration using the extended syntax:
view_filters:
filters:
- name: drafts
label: Drafts
field: draft
pattern: true
- name: posts_2024
label: Posts from 2024
field: date
pattern: '^2024'
- name: travel_or_food
label: Travel or Food
field: category
pattern: travel|food
default: draftsIn this syntax, each filter needs a name, so that the default option can refer to it. The default option has to be the name of one of the filters. Any other name is reported as a config validation error on the login screen, because the collection would otherwise open unfiltered.
Comparing Values
A view filter can compare the field value with a given value instead of, or in addition to, matching a pattern. This makes it possible to filter entries by a date, such as upcoming and past events, or by a number, such as products above a certain price. The following options are available:
| Option | Description |
|---|---|
eq | The field value has to be equal to the given value. |
ne | The field value has to be different from the given value. |
lt | The field value has to be less than the given value. |
lte | The field value has to be less than or equal to the given value. |
gt | The field value has to be greater than the given value. |
gte | The field value has to be greater than or equal to the given value. |
in | The field value has to be equal to one of the given values, defined as an array. |
not_in | The field value has to be different from all the given values, defined as an array. |
empty | The field value has to be empty (true) or not (false). |
The value of a DateTime field is compared as a date, so the given value has to be in the same format as the field value, or one of the following template tags:
| Tag | Description |
|---|---|
{{now}} | The current date and time. |
{{today}} | The current date in the YYYY-MM-DD format. Use this rather than {{now}} with a date-only field, so that an entry dated today is included in a gte comparison. |
{{year}}, {{month}}, {{day}}, {{hour}}, {{minute}}, {{second}} | The parts of the current date and time, which can also be used in a pattern, e.g. ^{{year}} for the entries of this year. |
The tags are resolved in the user’s local timezone whenever the entry list is updated, and every minute while such a filter or group is applied, so a filter like “Upcoming events” keeps working without any change to the configuration.
A number field value and a numeric given value are compared as numbers. Any other value is compared as a string. An entry without a value for the field only matches ne, not_in and empty: true. When several options are defined for one filter, all of them have to be satisfied.
The empty option tells the entries that have a value for the field from those that don’t. A value is empty if:
- it’s
null, an empty string or an empty list - it’s an Object field whose subfields are all empty
- the field is missing from the entry altogether, for example because the field was added to the configuration after the entry was created
Use this rather than eq or ne, which can’t express a missing value in TOML, where there is no null:
view_filters:
- label: With author
field: author
empty: false
- label: Without author
field: author
empty: true[[collections.view_filters]]
label = "With author"
field = "author"
empty = false
[[collections.view_filters]]
label = "Without author"
field = "author"
empty = true{
"view_filters": [
{ "label": "With author", "field": "author", "empty": false },
{ "label": "Without author", "field": "author", "empty": true }
]
}{
view_filters: [
{ label: "With author", field: "author", empty: false },
{ label: "Without author", field: "author", empty: true },
],
}The comparison options can also be used with the extended syntax described above, for example to apply the “Upcoming” filter by default:
view_filters:
filters:
- name: upcoming
label: Upcoming
field: date
gte: '{{today}}'
- name: past
label: Past
field: date
lt: '{{today}}'
default: upcomingThe example below defines the filters for a list of events:
collections:
- name: events
label: Events
folder: /content/events
fields:
- { name: title, label: Title }
- { name: date, label: Date, widget: datetime, time_format: false }
- { name: capacity, label: Capacity, widget: number }
- { name: status, label: Status, widget: select, options: [scheduled, canceled] }
view_filters:
- label: Upcoming
field: date
gte: '{{today}}'
- label: Past
field: date
lt: '{{today}}'
- label: This year
field: date
pattern: '^{{year}}'
- label: Large venues
field: capacity
gte: 100
- label: Not canceled
field: status
ne: canceled[[collections]]
name = "events"
label = "Events"
folder = "/content/events"
[[collections.fields]]
name = "title"
label = "Title"
[[collections.fields]]
name = "date"
label = "Date"
widget = "datetime"
time_format = false
[[collections.fields]]
name = "capacity"
label = "Capacity"
widget = "number"
[[collections.fields]]
name = "status"
label = "Status"
widget = "select"
options = ["scheduled", "canceled"]
[[collections.view_filters]]
label = "Upcoming"
field = "date"
gte = "{{today}}"
[[collections.view_filters]]
label = "Past"
field = "date"
lt = "{{today}}"
[[collections.view_filters]]
label = "This year"
field = "date"
pattern = "^{{year}}"
[[collections.view_filters]]
label = "Large venues"
field = "capacity"
gte = 100
[[collections.view_filters]]
label = "Not canceled"
field = "status"
ne = "canceled"{
"collections": [
{
"name": "events",
"label": "Events",
"folder": "/content/events",
"fields": [
{ "name": "title", "label": "Title" },
{ "name": "date", "label": "Date", "widget": "datetime", "time_format": false },
{ "name": "capacity", "label": "Capacity", "widget": "number" },
{ "name": "status", "label": "Status", "widget": "select", "options": ["scheduled", "canceled"] }
],
"view_filters": [
{
"label": "Upcoming",
"field": "date",
"gte": "{{today}}"
},
{
"label": "Past",
"field": "date",
"lt": "{{today}}"
},
{
"label": "This year",
"field": "date",
"pattern": "^{{year}}"
},
{
"label": "Large venues",
"field": "capacity",
"gte": 100
},
{
"label": "Not canceled",
"field": "status",
"ne": "canceled"
}
]
}
]
}{
collections: [
{
name: "events",
label: "Events",
folder: "/content/events",
fields: [
{ name: "title", label: "Title" },
{ name: "date", label: "Date", widget: "datetime", time_format: false },
{ name: "capacity", label: "Capacity", widget: "number" },
{ name: "status", label: "Status", widget: "select", options: ["scheduled", "canceled"] },
],
view_filters: [
{
label: "Upcoming",
field: "date",
gte: "{{today}}",
},
{
label: "Past",
field: "date",
lt: "{{today}}",
},
{
label: "This year",
field: "date",
pattern: "^{{year}}",
},
{
label: "Large venues",
field: "capacity",
gte: 100,
},
{
label: "Not canceled",
field: "status",
ne: "canceled",
},
],
},
],
}