Skip to content

How-Tos

This section provides practical guides on how to implement common features and use cases with Sveltia CMS.

Using Entry Tags for Categorization

If you write blog posts, for example, you may want to categorize them with taxonomies, often called tags, categories, labels or keywords. With Sveltia CMS, there are several ways to implement this feature, depending on your needs.

If you don’t have a predefined list of tags, you can use a simple List field. This configuration will produce a newline-separated text field where users can enter tags freely:

yaml
collections:
  - name: posts
    label: Blog Posts
    label_singular: Blog Post
    folder: /content/posts
    fields:
      - name: title
        label: Title
      - name: tags
        label: Tags
        widget: list
      - name: body
        label: Body
        widget: richtext
toml
[[collections]]
name = "posts"
label = "Blog Posts"
label_singular = "Blog Post"
folder = "/content/posts"

[[collections.fields]]
name = "title"
label = "Title"

[[collections.fields]]
name = "tags"
label = "Tags"
widget = "list"

[[collections.fields]]
name = "body"
label = "Body"
widget = "richtext"
json
{
  "collections": [
    {
      "name": "posts",
      "label": "Blog Posts",
      "label_singular": "Blog Post",
      "folder": "/content/posts",
      "fields": [
        {
          "name": "title",
          "label": "Title"
        },
        {
          "name": "tags",
          "label": "Tags",
          "widget": "list"
        },
        {
          "name": "body",
          "label": "Body",
          "widget": "richtext"
        }
      ]
    }
  ]
}
js
{
  collections: [
    {
      name: "posts",
      label: "Blog Posts",
      label_singular: "Blog Post",
      folder: "/content/posts",
      fields: [
        {
          name: "title",
          label: "Title",
        },
        {
          name: "tags",
          label: "Tags",
          widget: "list",
        },
        {
          name: "body",
          label: "Body",
          widget: "richtext",
        },
      ],
    },
  ],
}

If you have a small number of predefined tags, you can use a Select field. This configuration will produce a dropdown list where users can select one or more tags:

yaml
fields:
  - name: tags
    label: Tags
    widget: select
    multiple: true
    options:
      - { label: Travel, value: travel }
      - { label: Food, value: food }
      - { label: Technology, value: technology }
      - { label: Lifestyle, value: lifestyle }
toml
[[fields]]
name = "tags"
label = "Tags"
widget = "select"
multiple = true

[[fields.options]]
label = "Travel"
value = "travel"

[[fields.options]]
label = "Food"
value = "food"

[[fields.options]]
label = "Technology"
value = "technology"

[[fields.options]]
label = "Lifestyle"
value = "lifestyle"
json
{
  "fields": [
    {
      "name": "tags",
      "label": "Tags",
      "widget": "select",
      "multiple": true,
      "options": [
        { "label": "Travel", "value": "travel" },
        { "label": "Food", "value": "food" },
        { "label": "Technology", "value": "technology" },
        { "label": "Lifestyle", "value": "lifestyle" }
      ]
    }
  ]
}
js
{
  fields: [
    {
      name: "tags",
      label: "Tags",
      widget: "select",
      multiple: true,
      options: [
        { label: "Travel", value: "travel" },
        { label: "Food", value: "food" },
        { label: "Technology", value: "technology" },
        { label: "Lifestyle", value: "lifestyle" },
      ],
    },
  ],
}

If you want more flexibility, you can create a separate collection for tags and reference it using a Relation field from your blog post collection. This approach allows you to:

  • Add many tags without bloating the configuration file
  • Manage tags in one place within the CMS
  • Reuse tags across multiple collections
  • Add a description, image and other details to each tag (if you have tag index pages)
  • Localize tags with i18n support enabled

This configuration will also produce a dropdown list where users can select one or more tags:

yaml
fields:
  - name: tags
    label: Tags
    widget: relation
    multiple: true
    collection: tags
    search_fields: [title]
    display_fields: [title]
    value_field: '{{slug}}'
toml
[[fields]]
name = "tags"
label = "Tags"
widget = "relation"
multiple = true
collection = "tags"
search_fields = ["title"]
display_fields = ["title"]
value_field = "{{slug}}"
json
{
  "fields": [
    {
      "name": "tags",
      "label": "Tags",
      "widget": "relation",
      "multiple": true,
      "collection": "tags",
      "search_fields": ["title"],
      "display_fields": ["title"],
      "value_field": "{{slug}}"
    }
  ]
}
js
{
  fields: [
    {
      name: "tags",
      label: "Tags",
      widget: "relation",
      multiple: true,
      collection: "tags",
      search_fields: ["title"],
      display_fields: ["title"],
      value_field: "{{slug}}",
    },
  ],
}

And here is an example of the corresponding tag collection:

yaml
collections:
  - name: tags
    label: Tags
    label_singular: Tag
    folder: /content/tags
    fields:
      - name: title
        label: Title
      - name: description
        label: Description
        widget: text
        required: false
      - name: image
        label: Image
        widget: image
        required: false
toml
[[collections]]
name = "tags"
label = "Tags"
label_singular = "Tag"
folder = "/content/tags"

[[collections.fields]]
name = "title"
label = "Title"

[[collections.fields]]
name = "description"
label = "Description"
widget = "text"
required = false

[[collections.fields]]
name = "image"
label = "Image"
widget = "image"
required = false
json
{
  "collections": [
    {
      "name": "tags",
      "label": "Tags",
      "label_singular": "Tag",
      "folder": "/content/tags",
      "fields": [
        {
          "name": "title",
          "label": "Title"
        },
        {
          "name": "description",
          "label": "Description",
          "widget": "text",
          "required": false
        },
        {
          "name": "image",
          "label": "Image",
          "widget": "image",
          "required": false
        }
      ]
    }
  ]
}
js
{
  collections: [
    {
      name: "tags",
      label: "Tags",
      label_singular: "Tag",
      folder: "/content/tags",
      fields: [
        {
          name: "title",
          label: "Title",
        },
        {
          name: "description",
          label: "Description",
          widget: "text",
          required: false,
        },
        {
          name: "image",
          label: "Image",
          widget: "image",
          required: false,
        },
      ],
    },
  ],
}

Note that it’s not currently possible to add new tags on the fly while editing a blog post. You have to create them in the tag collection first. This issue will be resolved in the future. (#493)

Editing Raw Text Files

Sveltia CMS allows users to edit raw text files without any front matter, such as JSON, XML, or CSV files. To achieve this, you can use the raw format in a file collection with a single body field configured with the appropriate widget type: code, markdown, richtext or text.

Here is an example configuration for editing the README.md and package.json files:

yaml
collections:
  - name: root_files
    label: Root Files
    editor:
      preview: false
    files:
      - name: readme
        label: README
        file: README.md
        format: raw
        fields:
          - name: body
            label: README.md
            widget: richtext
      - name: package_json
        label: package.json
        file: package.json
        format: raw
        fields:
          - name: body
            label: package.json
            widget: code
            output_code_only: true
            allow_language_selection: false
            default_language: json
toml
[[collections]]
name = "root_files"
label = "Root Files"
[collections.editor]
preview = false
[[collections.files]]
name = "readme"
label = "README"
file = "README.md"
format = "raw"
[[collections.files.fields]]
name = "body"
label = "README.md"
widget = "richtext"
[[collections.files]]
name = "package_json"
label = "package.json"
file = "package.json"
format = "raw"
[[collections.files.fields]]
name = "body"
label = "package.json"
widget = "code"
output_code_only = true
allow_language_selection = false
default_language = "json"
json
{
  "collections": [
    {
      "name": "root_files",
      "label": "Root Files",
      "editor": {
        "preview": false
      },
      "files": [
        {
          "name": "readme",
          "label": "README",
          "file": "README.md",
          "format": "raw",
          "fields": [
            {
              "name": "body",
              "label": "README.md",
              "widget": "richtext"
            }
          ]
        },
        {
          "name": "package_json",
          "label": "package.json",
          "file": "package.json",
          "format": "raw",
          "fields": [
            {
              "name": "body",
              "label": "package.json",
              "widget": "code",
              "output_code_only": true,
              "allow_language_selection": false,
              "default_language": "json"
            }
          ]
        }
      ]
    }
  ]
}
js
{
  collections: [
    {
      name: "root_files",
      label: "Root Files",
      editor: {
        preview: false,
      },
      files: [
        {
          name: "readme",
          label: "README",
          file: "README.md",
          format: "raw",
          fields: [
            {
              name: "body",
              label: "README.md",
              widget: "richtext",
            },
          ],
        },
        {
          name: "package_json",
          label: "package.json",
          file: "package.json",
          format: "raw",
          fields: [
            {
              name: "body",
              label: "package.json",
              widget: "code",
              output_code_only: true,
              allow_language_selection: false,
              default_language: "json",
            },
          ],
        },
      ],
    },
  ],
}

Editing Site Deployment Configuration Files

Sveltia CMS allows users to edit files without extensions. Examples include _headers and _redirects, which are used by some static site hosting providers, such as Netlify, GitLab Pages and Cloudflare Pages.

Since the body field is saved without the field name when using the default yaml-frontmatter format, you can use the following configuration to edit these files in the Content Editor. Or you can explicitly set the format option to raw, just like in the previous section.

yaml
collections:
  - name: config
    label: Site Configuration
    editor:
      preview: false
    files:
      - name: headers
        label: Headers
        file: static/_headers # The path varies by framework
        fields:
          - name: body
            label: Headers
            widget: code # Can also be `text`
            output_code_only: true
            allow_language_selection: false
      - name: redirects
        label: Redirects
        file: static/_redirects # The path varies by framework
        fields:
          - name: body
            label: Redirects
            widget: code # Can also be `text`
            output_code_only: true
            allow_language_selection: false
toml
[[collections]]
name = "config"
label = "Site Configuration"

[collections.editor]
preview = false

[[collections.files]]
name = "headers"
label = "Headers"
file = "static/_headers"

[[collections.files.fields]]
name = "body"
label = "Headers"
widget = "code"
output_code_only = true
allow_language_selection = false

[[collections.files]]
name = "redirects"
label = "Redirects"
file = "static/_redirects"

[[collections.files.fields]]
name = "body"
label = "Redirects"
widget = "code"
output_code_only = true
allow_language_selection = false
json
{
  "collections": [
    {
      "name": "config",
      "label": "Site Configuration",
      "editor": {
        "preview": false
      },
      "files": [
        {
          "name": "headers",
          "label": "Headers",
          "file": "static/_headers",
          "fields": [
            {
              "name": "body",
              "label": "Headers",
              "widget": "code",
              "output_code_only": true,
              "allow_language_selection": false
            }
          ]
        },
        {
          "name": "redirects",
          "label": "Redirects",
          "file": "static/_redirects",
          "fields": [
            {
              "name": "body",
              "label": "Redirects",
              "widget": "code",
              "output_code_only": true,
              "allow_language_selection": false
            }
          ]
        }
      ]
    }
  ]
}
js
{
  collections: [
    {
      name: "config",
      label: "Site Configuration",
      editor: {
        preview: false,
      },
      files: [
        {
          name: "headers",
          label: "Headers",
          file: "static/_headers",
          fields: [
            {
              name: "body",
              label: "Headers",
              widget: "code",
              output_code_only: true,
              allow_language_selection: false,
            },
          ],
        },
        {
          name: "redirects",
          label: "Redirects",
          file: "static/_redirects",
          fields: [
            {
              name: "body",
              label: "Redirects",
              widget: "code",
              output_code_only: true,
              allow_language_selection: false,
            },
          ],
        },
      ],
    },
  ],
}

Creating Conditional Fields

Sometimes, you may want to create your content model in a flexible way. Sveltia CMS does not support dependent fields yet, but you can achieve similar functionality using variable types in List and Object fields. This approach lets you make fields that can hold different types of data based on what the user chooses. Look at the documentation for each field to see examples.

Rendering Soft Line Breaks as Hard Line Breaks in Markdown

In the rich text editor, pressing Shift+Enter inserts a soft line break (\n). We can’t change the behavior to add a hard line break (<br>) — it’s a limitation of the underlying Lexical framework. However, if you look at the preview, you may notice that soft line breaks are rendered as hard line breaks. That’s because the preview is using the Marked library with the breaks option enabled, which mimics how comments are rendered on GitHub.

Chances are the Markdown parser you use for your frontend can do the same:

  • markdown-it (used in Eleventy and VitePress) also has the breaks option
  • remarkable also has the breaks option
  • Showdown has the simpleLineBreaks option
  • goldmark (used in Hugo) has the html.WithHardWraps option
  • kramdown (used in Jekyll) has the hard_wrap option with the GFM parser
  • remark (used in Astro) offers a plugin
  • micromark clarifies it doesn’t have such an option and recommends alternatives

Released under the MIT License.