ūüĆĪ The next big step: Kirby 4 Alpha Learn more
Skip to content

Kirby 4


The gist of it

Kirby 4 Chameleon

Kirby 4 will launch in 2023

We are very excited to announce the first test version for Kirby 4 with many great user-facing features and improvements. We want share our progress with you out in the open in the coming weeks. Final release of v4 is scheduled for later this summer. ūüöÄ

All licenses purchased in 2023 qualify as Kirby 4 licenses

We will treat any license bought on or after 1 Jan 2023 as if you bought it on the day of the v4 release. Older licenses that have not been activated yet will qualify as well. For older active licenses we will offer very fair upgrade prices as always.


Kirby 4 will be built upon the healthy code base we established for Kirby 3. Upgrades will be comparable to a 3.x release. While we stay on the same architecture, this new version will bring many long-awaited features and is going to move your projects forward.


ETA for Kirby 4

We roughly plan with the following schedule for v4. The success of the alpha & beta and your input will determine the final release date.

  • Alpha

    May 2023

  • Beta

    July 2023

  • Release

    Late summer 2023


We are not done yet ‚Ķ

This is the very first public test version of Kirby 4. Now it's time for you to get involved. We need your honest feedback and your eagle eyes to find bugs. We plan to build more features in the next weeks. You can follow our process on Discord.

Read more …

This version is very likely buggy.
That's why we call it alpha :)

Do not use it in production!

Page creation dialogs

Faster, better page creation

Customize the page creation dialog to your needs.

Give the title a fitting label, add new fields or disable redirecting to the new page. Did we mention you can also define the initial page status after creation now?

Read more …

title: Product
    label: Product name
    - price
    - brand
  redirect: false
  status: listed

Moving pages

I like to move it, move it

A new parent for the page can be picked with our brand new page tree dialog

Created a page in the wrong place or made up your mind? Just move it to a new parent!

Read more …

The page dropdowns have been extended with the new Move page option

Section filters

Filter pages and files

An example for a shop with filtered products by price range

Filter pages and files by any criteria: The pages and files sections now come with support for our powerful query string syntax.

Read more …

  extends: sections/products
  label: Expensive
  query: page.childrenAndDrafts.filter('price', '>', '99')
  extends: sections/products
  label: Cheap
  query: page.childrenAndDrafts.filter('price', '<=', '99')

Color field

Color me surprised

Color in all its facets: Multiple color notations, color picker, pre-defined colors, custom color names and transparency. You can't get more color than that.

Read more …

The new color field with the color picker dropdown and predefined colors with names
  type: color
    "Sunny rays": "#F8B195"
    "First-love blush": "#F67280"
    "Cherry blossom": "#C06C84"
    "Morning gloom": "#6C5B7B"
    "Midnight rain": "#355C7D"
The color field can be simplified to show a set of predefined colors instead of offering a color picker

Image focus

Focus Pocus

The focus point for images can now be set directly in the file view. Drop a marker on the most relevant point in the image to always crop around a custom center point.

Never cut off the most important part of your images again. Set a focus point and let your images shine in all their beauty.

Read more …


Uploading files the smart way

The new upload dialog with four images, ready to be uploaded. Each file has a new input to change the filename before the file gets uploaded.

Screenshot-123.jpg? With the preview and edit options in the new upload dialog, meaningless file names are now a thing of the past. Use the new blueprint options to optimize uploads before they land on the server.

Read more …

title: Image

# Optimize on upload
  width: 500
  height: 500
  crop: true

Block field improvements

Our best field is now 25% bester

The new field preview for blocks lets you edit block content directly in form fields instead of a live block preview
    type: blocks
        wysiwyg: true
        preview: fields
                type: text
                type: text
                type: writer
            label: Settings
            fields: # ...

Display and edit headings level inline

The heading level is now displayed right next to the heading and can be used to change the level on the fly

New toggles inside the drawer

The heading level can also be set with the new toggles in the block drawer

Block splitting

  • Split and merge text, list and headings
  • New option buttons to split or merge
  • Press enter at the end of a headline to append a new text block
  • Text block with¬†inline: true¬†for text field will split directly on Enter (Shift + Enter creates a hard line break)
  • Custom blocks can support splitting by implementing a¬†split¬†method

Read more …

Minimized blocks while dragging

Blocks are now minimized while you drag them around. This makes it easier to sort blocks with long content.

New Keyboard shortcuts

Action Shortcut
Remove block Meta + Backspace
Move focus up Meta + ↑
Move focus down Meta + ↓
Move block up Meta + Shift + ↑
Move block down Meta + Shift + ↓
Extend selection up Meta + Alt + ↑
Extend selection down Meta + Alt + ↓
Split block Meta + Enter
Merge block Meta + J

Layout field improvements

Copy & Change

More flexibility: Simply change a layout, and copy one or all layouts into other layout fields.

Read more …

New copy, paste and change layout options in the layout dropdown

Language editor

No longer lost in translation

The new language view with general information about the language and the new language variable editor.

Each language got its own view now. Easily configure your languages or edit language variables right from the Panel. Easy, right?

Read more …

Search view

Deliver results

The new search view with a long list of results for a file search.

The larger your website, the more important becomes search. With Kirby's new search view, searching in the Panel has become a breeze.

Read more …

Changeable file templates

Change is in the air

The new dialog to change the template of a file.

Change file templates to any allowed template defined by its parent in a files section or field.

Read more …

Writer field improvements

Writing in style

With custom marks and nodes for your own style, customizable heading levels and a character counter, you have full control about your writing.

Read more …

The updated writer field with the new toolbar option that resembles the fixed toolbar of the textarea
The link picker for the writer now also features the new link field

Link to internal pages & files with our new link field in the link dialog. No more guessing of URLs.

Toolbar position + layout
    type: writer
      inline: false
        - bold
        - "|"
        - link
    type: writer
      - 2
      - 3
      - 4
New marks
    type: writer
      - sub
      - sup
      - clear
    type: writer
    minlength: 10
    maxlength: 360
    counter: false

Writer Plugins

You need a block or inline format that’s not available? Create your own marks and nodes with our brand new extension API for Writer plugins.

Read more …

panel.plugin("acme/writer", {
  writerNodes: {
    blockquote: {
      // ...
  writerMarks: {
    mention: {
      // ...

Custom textarea buttons

Bring your own

Missing that one special button for your custom text markup? Make one.

Read more …

panel.plugin("acme/textarea", {
  textareaButtons: {
    marquee: {
      label: "Marquee",
      icon: "wand",
      command(input, selection) {
        this.command("insert", (input, selection) => {
          return "<marquee>" + selection + "</marquee>";
      shortcut: "m"

Srcset in image tag

Image tag goes responsive

The image KirbyTag has turned responsive. The srcset attribute supports manual settings and presets.

Read more …

With absolute sizes

(image: alanis-moresrcset.jpg srcset: 200, 300)

With predefined srcset

(image: alanis-moresrcset.jpg srcset: artist)

Default page model

Set a new page standard


use Kirby\Cms\Page;

class DefaultPage extends Page
     * This method is now available for all pages
     * unless they have their own page model.
    public function myCustomMethod(): string
        return 'Hello world';

The default page model kicks in when there is no specific model for a page.

Of course, other models can extend the default page model, too.

Read more …

Panel JavaScript API

Remote control

Our new Panel JavaScript API gives you access to the most important Panel features. Control dialogs, drawers, notifications and more from your plugins, your custom panel.js or even the console.

Read more …

All major Panel features can now be controlled directly from your browser console

New Versioning Scheme

Semantic Versioning

{generation} {major} {minor} {patch}
3 9 0 0
3 10 0 0
3 11 0 0
{generation} {major} {minor} {patch}
3 3 9 0
4 0 0
5 0 0

Key points

  • Kirby will follow semantic versioning
  • Major versions will no longer be automatically bound to paid upgrades
  • Major versions will be released on a yearly cycle to bring continuity and planning security.

Example roadmap

  • 4.0.0: late summer 2023
  • 5.0.0: late summer 2024
  • 6.0.0: late summer 2025

Frequently asked questions

We are getting a lot of questions after our announcement and already tried to answer most of them here. We will keep collecting questions from the community here and try to answer them as transparently as possible. Let us know on Discord or in the Forum if you have additional questions.

What happens with licenses purchased before 2023?

We really appreciate the support of everyone who uses our volume discounts to purchase licenses in advance and we don't want to break the trust that comes with such purchases.

All unused v3 licenses, which have not been activated before 1.1.2023 will be upgraded to v4 for free as well.

What will happen with Kirby 3?

Kirby 3 will receive security support for quite a while after the launch of Kirby 4. The launch of Kirby 4 will not mean that you have to rebuild all your old projects.

The decision to build on the Kirby 3 architecture also means that you have a better chance for upgrades of old projects this time and we have a better chance to provide security support for Kirby 3 because it's not a completely different codebase.

What will Kirby‚Äôs future licensing model look like?
  • No subscription
  • One-time purchase that allows to keep using the purchased version
  • Updates to a reasonable amount of new major versions will be included with each purchase
  • More details to be announced



Core improvements

Support for UUIDs in URL helper

You can now pass a page UUID or a file UUID to the url() helper and it will be converted to the actual URL:

<?= url('page://abcd') ?>
<?= url('file://abcd') ?>

This will also work for other URL methods like. $field->toUrl(), Url:to(), etc.

Support for UUIDs in API calls

You can now use UUIDs in API calls to request pages and files. #4769


The UUIDs must be passed without scheme, but a prefixed @. I.e.:

// Nope

// Yes

File routes can also handle file UUIDs for files and parents:


In addition to that there are new direct UUID file routes:


More improvements

  • New¬†File::blueprints()¬†method that collects valid blueprints from the files sections and files fields of the parent model
  • Fields can now define¬†'hidden' => true¬†(component notation) or¬†::isHidden(): bool¬†(class-based) to make them non-rendering¬†
  • New¬†File::changeTemplate()¬†method
  • New file permissions for¬†changeTemplate
  • New¬†file.changeTemplate¬†hooks
  • New¬†Kirby\Email\Email::toArray()¬†and¬†Kirby\Email\Body::toArray()¬†methods
  • New Kirby\Exception\AuthException class

Panel improvements

Dialogs for fields

Fields can now define their own dialogs on the backend.

  • Fields with array definition:

    return [
    'props' => [
      // ...
    'dialogs' => function () {
      return [
          'pattern' => 'delete',
          'load' => function () {},
          'submit' => function () {},

  • Field classes:

    class MyField extends FieldClass
    public function dialogs(): array
      return [
          'pattern' => 'delete',
          'load' => function () {},
          'submit' => function () {},

The route patterns for field dialogs are automatically prefixed with the following scheme:


Here's an example:


In a field component, the dialog can be opened by using the field endpoint:

this.$dialog(this.endpoints.field + "/delete")

New Icons

We've added new icons to our Panel iconset:

  • clear
  • split
  • merge

New Components

  • <k-code>
  • <k-dialog-body>
  • <k-dialog-box>
  • <k-dialog-buttons>
  • <k-dialog-fields>
  • <k-dialog-footer>
  • <k-dialog-form>
  • <k-dialog-notification>
  • <k-dialog-search>
  • <k-dialog-text>
  • <k-notification>
  • <k-drawer-body>
  • <k-drawer-fields>
  • <k-drawer-header>
  • <k-drawer-notification>
  • <k-drawer-tabs>
  • <k-tree>
  • <k-page-tree>
  • <k-browser>
  • <k-file-browser>

New helpers

  • $helper.focus(element)
  • $helper.object.length(object)
  • $helper.string.isEmpty(string)
  • $helper.url.base
  • $helper.url.buildQuery
  • $helper.url.buildUrl
  • $helper.url.isAbsolute
  • $helper.url.isSameOrigin
  • $helper.url.isUrl
  • $helper.url.makeAbsolute
  • $helper.url.toObject

New JS error classes

  • RequestError
  • JsonRequestError

More to come …

We are not done here …

Bug fixes

  • Removed flickering from¬†k-pagination¬†when navigating
  • Fixed name of default blueprints to¬†pages/default and files/default
  • Blocks: batch selection allows deselecting blocks
  • Blocks: batch selection gets deselected on Escape key
  • Fixed i18n translate issues, e.g. for the user blueprint title¬†#4869
  • Writer field: Email mark toolbar button title is properly translated now
  • Empty required Writer field now shows proper invalid styling in Panel
  • UUIDs are less often generated when not needed to be generated
  • Kirby queries now differentiate between integers and floats as arguments
  • Kirby no longer hides errors in the response class when the response is converted to a string:¬†#5027




  • Cleaned up¬†k-toolbar¬†component

  • Drawer Component Structure

    <k-overlay type="drawer">
      <form class="k-drawer" method="dialog">
          <k-drawer-notification />
          <k-drawer-header />
              <k-drawer-fields />
  • Portals: Dialogs, Drawers and other Overlays are now seperated into different portals. This is done by setting the overlay type:

    • <k-overlay type="dialog">
    • <k-overlay type="drawer">
    • <k-overlay>
      An overlay without a type will use the default overlay portal. Separating them into different portals gives us more control over z-index and layering of elements.
  • Removed¬†v-model¬†from¬†k-form¬†and¬†k-fieldset

  • Removed $listeners usage from k-draggable, k-button¬†and subcomponents, k-link, k-headline, k-form, k-block, k-block-title, k-box, k-image, k-content-item




  • this.$events: Use¬†this.$panel.events¬†instead.
  • this.$panel.events.$on: Use¬†this.$panel.events.on¬†instead
  • this.$panel.events.$off: Use¬†this.$panel.events.off¬†instead
  • this.$panel.events.$emit: Use¬†this.$panel.events.emit¬†instead
  • this.$store.dispatch("isLoading"): Use this.$panel.isLoading¬†instead
  • this.$translation: Use¬†this.$panel.translation¬†instead
  • this.$store.dispatch("dialog")¬†is deprecated. Use¬†this.$panel.dialog.open¬†and¬†this.$panel.dialog.close¬†instead
  • this.$store.dispatch("drag", drag)¬†has been deprecated. Use¬†this.$panel.drag = drag¬†instead

Breaking changes

Removed deprecated code



  • this.$library.autosize¬†has been removed, wrap <textarea> elements inside <k-autosize> element instead.
  • Defining the footer slot in <k-dialog> will no longer wrap the slot content in the <footer> element. This can now be more flexibly handled by using <k-dialog-footer> inside the slot.
  • The form drawer no longer automatically closes on submit. This is introducing the same behaviour as in dialogs. Auto-closing might often not be the intended result of submitting the form and it's easier to close it manually in a submit handler than to re-open it again.
  • this.$store.state.isLoading¬†is no longer available. You can now use¬†window.panel.isLoading¬†or¬†this.$panel.isLoading¬†in Vue components to access the current loading state.
  • this.$store.state.dialog¬†is no longer available. Use¬†this.$panel.dialog¬†instead.
  • Removed¬†this.$store.state.drag, use¬†window.panel.drag/this.$panel.drag¬†instead.
  • k-button¬†,¬†k-link,¬†k-headline and k-content-item only emit the¬†click¬†event. For other native events, use the¬†.native¬†event listener modifier
  • Native events (e.g.¬†click,¬†dbclick) need the¬†.native¬†modifier now when used on¬†k-block¬†and¬†k-block-title
  • Need to use¬†.native¬†modifier for all previous event listeners on¬†k-box and¬†k-image

Get started