Markdown
If you create a Markdown file under the src/jsMain/resources/markdown
folder, a corresponding page will be created for you at build time, using the filename as its path.
For example, if I create the following file:
this will create a page that I can then visit by going to mysite.com/docs/tutorial/kobweb
Front Matter
Front Matter is metadata that you can specify at the beginning of your document, like so:
You can then query these key / value pairs using the page's PageContext:
If you're not seeing ctx.markdown
autocomplete, you need to make sure you depend on the com.varabyte.kobwebx:kobwebx-markdown
artifact in your project's build script.
Root
Within your front matter, there's a special value which, if set, will be used to render a root @Composable
that wraps the rest of your Markdown code as its content. This is useful for specifying a layout for example:
The above will generate code like the following:
You may have noticed that the code path above is prefixed with a .
(here, .components.layouts.DocsLayout
). Whenever you do that in Kobweb Markdown, the framework will detect it and convert it to your site's full package.
If you have a default root that you'd like to use in most / all of your Markdown files, you can specify it in the markdown
block in your build script:
Route Override
Kobweb Markdown front matter supports a routeOverride
key. If present, its value will be passed into the generated @Page
annotation ( Route override).
This allows you to give your URL a name that normal Kotlin filename rules don't allow for, such as a hyphen:
# AStarDemo.md
The above will generate code like the following:
Kobweb Call
The power of Kotlin + Compose HTML is interactive components, not static text! Therefore, Kobweb Markdown support enables special syntax that can be used to insert live Kotlin code into your page.
Block syntax
Usually, you will define widgets that stand alone, without text or other components crowding around them. For this case, use three triple-curly braces (this of this like Markdown's triple ``` tick syntax, but for code):
This will generate code for you like the following:
Inline syntax
Occasionally, you may want to insert a smaller widget into the flow of a single sentence. For this case, use the ${...}
inline syntax:
Spaces are not allowed within the curly braces! If you have them there, Markdown skips over the whole thing and leaves it as text.
Imports
You may wish to add imports to the code generated from your Markdown. Kobweb Markdown supports registering both global imports (imports that will be added to every generated file) and local imports (those that will only apply to a single target file).
Global Imports
To register a global import, configure the markdown
block in your build script:
The above would ensure that every Markdown file generated would have the following import:
Imports can help you simplify your Kobweb calls. Revisiting an example from just above:
Local Imports
Local imports are specified in your Markdown's front matter (and can even be used by the root declaration!):
Callouts
Kobweb Markdown supports callouts, which are a way to highlight pieces of information in your document. For example, you can use them to highlight notes, tips, warnings, or important messages.
To use a callout, set the first line of some blockquoted text to [!TYPE]
, where TYPE is one of the following:
- CAUTION - Calls attention to something that the user should be extra careful about.
- IMPORTANT - Important context that the user should be aware of.
- NOTE - Neutral information that the user should notice, even when skimming.
- QUESTION - A question posed whose answer is left as an exercise to the reader.
- QUOTE - A direct quote.
- TIP - Advice that the user may find useful.
- WARNING - Information that a user should be aware of to prevent errors.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
If you'd like to change the value of the default title that shows up, you can specify it in quotes:
Interesting fact here!
As another example, when using quotes, you can set the label to the empty string:
which looks clean:
The trouble with quotes on the internet is you never know if they are genuine.
— Abraham Lincoln
If you want to specify a label that should apply globally, you can do so by overriding the blockquote handler in your project's build script, using the convenience method SilkCalloutBlockquoteHandler
for it:
Callouts are provided by Silk. If your project does not use Silk and you override the blockquote handler like this, it will generate code that will cause a compile error.
Callout variants
Silk provides a handful of variants for callouts.
For example, an outlined variant:
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
and a filled variant:
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
You can also combine any of the standard variants with an additional matching link variant (e.g. LeftBorderedCalloutVariant.then(MatchingLinkCalloutVariant))
) to make it so that any hyperlinks inside the callout will match the color of the callout itself:
A simple callout with an example link in the callout body.
A simple callout with an example link in the callout body.
A simple callout with an example link in the callout body.
If you prefer any of these styles over the default, you can set the variant
parameter in the SilkCalloutBlockquoteHandler
. For example, here we set it to the outlined variant:
You can also specify the variant from within the Markdown syntax, passing it in as a parameter using a curly brace syntax:
Of course, you can also define your own variant in your own codebase and use that here as well.
Custom callouts
If you'd like to register a custom callout, this is done in two parts.
First, declare your custom callout setup in your code somewhere:
and then register it in your build script, extending the default list of handlers (i.e. SilkCalloutTypes
) with your custom one:
That's it! At this point, you can use it in your Markdown:
Iterating over all markdown files
It can be really useful to process all Markdown files when your site is being built. A common example is to collect all Markdown articles and generate a listing page from them.
You can actually do this using pure Gradle code, but it is common enough that Kobweb provides a convenience API, via the markdown
block's process
callback.
You can register a callback that will be triggered at build time with a list of all Markdown files in your project.
Inside the callback, you can also call generateKotlin
and generateMarkdown
methods, to easily create files that will be included in your final site.
Here is a very rough example of creating a listing page for all blog posts in a site (found under the resources/markdown/blog
folder):
Refer to the build script of this site and search for "process.set" to see this feature in action in a production environment.
Markdown sources
A markdown source here means a folder or task that provides Markdown files.
Adding additional sources
As mentioned earlier, Kobweb will look for Markdown files in the src/jsMain/resources/markdown
folder, but you can add additional locations.
Perhaps the most common pattern users will use is to define a custom task which generates markdown files when it is run, and then call kobweb.markdown.addSource
passing that task in as a source:
If you add this code to your build script, then Kobweb will automatically run that task, ultimately generating a top-level /example
route for your site from the source markdown file.
Configuring a target package
By default, Kobweb assumes most users want to use Markdown to generate pages for their site. However, there are occasions you may want to use Markdown to generate a section of text.
You can accomplish this by associating a markdown source with a target package.
For example, let's say I'm working on a card game and I want to create a bunch of card descriptions from markdown. Let's say we want them to live in the com.mysite.components.sections.cards
package. Let's plan to create a new folder for cards, in src/jsMain/resources/card-sections
.
You can declare that directory as a markdown source and provide the desired package target:
When the package value starts with a .
, as above, Kobweb will automatically prefix it with your site's group for convenience. If you set the package to just "."
, then it will use your site's group as the package.
That's it! Now, any markdown files found under the card-sections
folder will be generated into src/jsMain/kotlin/com/mysite/components/sections/cards
as regular, non-page composables.
If you don't pass in a custom package with your source, the default value ".pages"
will be used.