Skip to content

Conversation

@bszyman
Copy link
Contributor

@bszyman bszyman commented Oct 5, 2025

πŸ“‹ Description

The original article seemed like it was written by AI maybe? It was mostly correct, just a few changes and clarifications to make.

πŸ“Ž Related Issues (if applicable)

#7425

βœ… Contributor Checklist

I've followed the Umbraco Documentation Style Guide and can confirm that:

  • Code blocks are correctly formatted.
  • Sentences are short and clear (preferably under 25 words).
  • Passive voice and first-person language (β€œwe”, β€œI”) are avoided.
  • Relevant pages are linked.
  • All links work and point to the correct resources.
  • Screenshots or diagrams are included if useful.
  • Any code examples or instructions have been tested.
  • Typos, broken links, and broken images are fixed.

Product & Version (if relevant)

v16

Deadline (if relevant)

N/A

πŸ“š Helpful Resources

@bszyman bszyman requested a review from sofietoft October 7, 2025 03:42
Copy link
Contributor

@AndyButland AndyButland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good to me @bszyman. I made a couple of suggestions you can consider for improvements.

Regarding the one about using UmbExtensionManifestKind, you'll need to verify that, but it is what I see in the source code so even if the syntax you have works, if what I've suggested does too then I think it's better to align with what people might see if they look into the CMS source code.

@nielslyngsoe
Copy link
Member

Hi @bszyman

Looks good, Ive added comments to Andy's comments above, just to confirm his perspectives.

I would like to add for a Kind to show up correctly in TypeScript. Especially relevant if your kinds are to be available for others. Then it is important also to define Types for the Kind.

For the particular example, it would look like this:

export interface CustomManifestHeaderAppButtonKind extends ManifestHeaderApp {
	type: 'customHeaderAppButton';
	kind: 'button';
	meta: MetaHeaderAppButtonKind;
}

export interface CustomMetaHeaderAppButtonKind {
	href: string;
	label: string;
	icon: string;
}

declare global {
	interface UmbExtensionManifestMap {
		CustomManifestHeaderAppButtonKind: CustomManifestHeaderAppButtonKind;
	}
}

This will give Intellisense when writing a Manifest of that Type and Kind.

For it to be available for others, as in if you are doing a package, that would be a bigger story, properly requiring some article describing how you need to publish your package on NPM and make an export of the package types. So the above 'Global' types can be declared in the tsconfig for the customizatin using CMS & the fictive package.

So similar to how we export extension-types, a package would need to do similar. See TSConfig of this part: https://docs.umbraco.com/umbraco-cms/customizing/development-flow#typescript-setup

Using a package that you like to utilize the Types of β€” would result in a tsconfig looking something like this:

{
    "compilerOptions": {
        ...
        "types": [
            "@umbraco-cms/backoffice/extension-types"
            "@custom-umbraco-package/extension-types"
        ]
    }
}

I hope that perspective makes sense, so that does invite for a Article on exporting types of your package, but the initial hint on how to declare Kind Types, just for internal use could be documented here :-)

@bszyman
Copy link
Contributor Author

bszyman commented Oct 22, 2025

@nielslyngsoe - Appreciate your suggestions!

What I've done in my sample project is added a file types.ts for my sample kind extension and added it adjacent to the manifests.ts file with all the kind manifest definitions.

image

And this is my code, mostly copying what you provided.

import type {
  ManifestHeaderApp,
  MetaHeaderAppButtonKind,
} from "@umbraco-cms/backoffice/extension-registry";

export interface CustomManifestHeaderAppButtonKind extends ManifestHeaderApp {
  type: "customHeaderAppButton";
  kind: "button";
  meta: MetaHeaderAppButtonKind;
}

export interface CustomMetaHeaderAppButtonKind {
  href: string;
  label: string;
  icon: string;
}

declare global {
  interface UmbExtensionManifestMap {
    CustomManifestHeaderAppButtonKind: CustomManifestHeaderAppButtonKind;
  }
}

TS doesn't like the "customHeaderAppButton" value. It seems like it wants either the type property to not be re-defined, or to be defined only as "headerApp".

image

I want to make sure I'm clear/not misunderstanding:

  1. These types will only be useful to other people who might be interested in using them, they're not needed to or useful for defining/implementing the manifests?

  2. The intent of "customHeaderAppButton". Is this supposed to match the name/alias of an extension in the manifest? Or would it be better to omit or use the suggested "headerApp"?

Copy link
Member

@nielslyngsoe nielslyngsoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @bszyman looks good, but the original examples was actualy correct. So now there is a bit of a mismatch, I think its because the context of the original examples was missing.
The fact that the referenced kind: 'button' is a Core kind, that the example uses. :-)

@nielslyngsoe
Copy link
Member

Hi @bszyman
I missed these questions:

`
I want to make sure I'm clear/not misunderstanding:

  1. These types will only be useful to other people who might be interested in using them, they're not needed to or useful for defining/implementing the manifests?

  2. The intent of "customHeaderAppButton". Is this supposed to match the name/alias of an extension in the manifest? Or would it be better to omit or use the suggested "headerApp"?`

there you go:

  1. Yes, but they are also useful for yourself. They are useful for anyone who likes to registere a manifest using this type. So Type safety for your self. If you make a package you much make them available so people can globally import them. (That particualary should be covered in another article so no worries on the specifics for a package)

  2. The kind, is like a preset for an existing extension-type, in this case your kind(preset) is for a HeaderApp, then the value must be 'headerApp'

I hope that helps :-)

@bszyman
Copy link
Contributor Author

bszyman commented Nov 21, 2025

@nielslyngsoe - Okay, that makes perfect sense!

This one has been confusing for me to revisit... it's like, a month or more old at this point and figuring out where we left off with it was challenging. But I see what you're saying now.

Fixed up, please give a second look when you have a moment! :)

alias: 'Umb.Kind.MyButtonKind',
matchType: 'headerApp',
matchKind: 'customHeaderAppButton',
matchKind: 'button',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry. My bad. Β΄buttonΒ΄ is a core kind. So that cannot be registered as a custom one.

So, yes, in this case, when bringing your own, then customHeaderAppButton is correct. Otherwise, it collides with the Core Kind. :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it just feels a little funny that the example brings something that already exists in Core. So that was properly something that confused me a bit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants