How to Implement Custom Bibliography Styles in Quarkdown: CSL and Native Methods
You can implement custom bibliography styles in Quarkdown by either adding a CSL XML file to your project resources or creating a Kotlin class that implements the BibliographyStyle interface with custom formatting logic.
Quarkdown’s bibliography system provides a flexible, three-layered architecture for formatting citations and reference lists. As implemented in iamgio/quarkdown, the pipeline delegates all presentation logic to pluggable style implementations, allowing you to customize bibliography styles in Quarkdown using either standard Citation Style Language (CSL) definitions or fully custom native code.
Understanding Quarkdown’s Bibliography Architecture
The bibliography pipeline consists of three distinct layers that work together to produce formatted output:
- Std-lib entry point – The
bibliographyfunction defined inBibliography.ktcreates aBibliographyViewAST node and delegates all formatting to aBibliographyStyleimplementation. - CSL-based implementation – The default
CslBibliographyStyleclass (seeCslBibliographyStyle.kt) loads CSL XML definitions using citeproc-java and lazily produces citation labels and entry content for every key. - AST rendering – Output renderers such as
QuarkdownHtmlNodeRenderer.ktandPlainTextNodeRenderer.ktconsume the formatted labels and content provided by the style to generate final HTML or plain text.
Method 1: Use a Custom CSL File
The simplest approach to implement custom bibliography styles in Quarkdown is to add a CSL XML file to your classpath and reference it by identifier.
First, add your CSL file to src/main/resources/styles/:
<!-- src/main/resources/styles/my-style.csl -->
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" version="1.0">
<info>
<title>My Custom Style</title>
<id>my-style</id>
</info>
<citation>
<layout delimiter=", ">
<text variable="author"/>
<text variable="issued" prefix=" (" suffix=")"/>
</layout>
</citation>
<bibliography>
<layout>
<text variable="author"/>
<text variable="title" prefix=". " suffix=". "/>
<text variable="container-title" suffix="."/>
</layout>
</bibliography>
</style>
Then reference the style in your Quarkdown document using the filename without extension:
.bibliography {references.bib} style:{my-style}
Behind the scenes, the bibliography function calls CslBibliographyStyle.from(style, …) at line 84 in Bibliography.kt. The factory method loads the CSL resource via BibliographyFileReader (lines 101–108 in CslBibliographyStyle.kt) and constructs a style-aware formatter that processes your .bib entries.
Method 2: Write a Native BibliographyStyle Implementation
For behavior that CSL cannot express—such as non-standard numbering schemes, custom HTML wrappers, or proprietary field handling—you must implement the BibliographyStyle interface directly.
Create a new Kotlin class in the com.quarkdown.core.bibliography.style package:
import com.quarkdown.core.bibliography.Bibliography
import com.quarkdown.core.bibliography.BibliographyEntry
import com.quarkdown.core.bibliography.style.BibliographyStyle
import com.quarkdown.core.bibliography.style.BibliographyEntryLabelProviderStrategy
import com.quarkdown.core.ast.InlineContent
import com.quarkdown.core.ast.base.inline.PlainText
class RomanNumberStyle(
private val bibliography: Bibliography
) : BibliographyStyle {
override val name = "roman"
override val labelProvider = object : BibliographyEntryLabelProviderStrategy {
private fun Int.toRoman(): String {
val romans = listOf(
1000 to "M", 900 to "CM", 500 to "D", 400 to "CD",
100 to "C", 90 to "XC", 50 to "L", 40 to "XL",
10 to "X", 9 to "IX", 5 to "V", 4 to "IV", 1 to "I"
)
var n = this
return buildString {
for ((value, symbol) in romans) {
while (n >= value) {
append(symbol)
n -= value
}
}
}
}
override fun getCitationLabel(entries: List<BibliographyEntry>) =
entries.joinToString(separator = "; ") { "[${it.citationKey}]" }
override fun getListLabel(entry: BibliographyEntry, index: Int) =
(index + 1).toRoman()
}
override fun contentOf(entry: BibliographyEntry): InlineContent =
listOf(PlainText("${entry.author}. ${entry.title}."))
}
To use this style, expose it via a custom std-lib module function or modify the existing bibliography function to instantiate your class when the style parameter matches your identifier (e.g., roman), falling back to CSL resolution if no native implementation is found.
Summary
- CSL files provide the fastest path to custom bibliography styles in Quarkdown—place XML files in
src/main/resources/styles/and reference them by filename in thestyleargument. - Native implementations of
BibliographyStyleoffer unlimited flexibility for custom logic, requiring only that you implementBibliographyEntryLabelProviderStrategyand thecontentOfmethod. - The
bibliographyfunction inBibliography.ktserves as the entry point, callingCslBibliographyStyle.fromat line 84 to resolve CSL-based styles. - Renderers in
QuarkdownHtmlNodeRenderer.ktandPlainTextNodeRenderer.ktautomatically consume the formatted output from any style implementation, ensuring consistent rendering across output formats.
Frequently Asked Questions
Can I use any CSL file from the Zotero repository?
Yes. Download any valid CSL XML file from the official Citation Style Language repository and place it in src/main/resources/styles/. Quarkdown’s BibliographyFileReader (from citeproc-java) parses the file at runtime when you reference its identifier in the style argument, as implemented in lines 101–108 of CslBibliographyStyle.kt.
What bibliography file formats does Quarkdown support?
According to the source code in CslBibliographyStyle.kt, the BibliographyFileReader supports BibTeX (.bib), CSL-JSON, YAML, EndNote, and RIS formats. The reader automatically detects the format from the file extension and content stream.
How do I register a custom native style for use in documents?
Create a class implementing BibliographyStyle, then expose it through a custom std-lib module function similar to the native bibliography function. Alternatively, modify the existing bibliography function in Bibliography.kt to instantiate your class when the style parameter matches a specific identifier, falling back to CSL resolution via CslBibliographyStyle.from if no custom match is found.
Does changing the bibliography style affect inline citation labels?
Yes. The labelProvider property of your BibliographyStyle implementation controls both the inline citation labels (via getCitationLabel) and the bibliography list labels (via getListLabel). The QuarkdownHtmlNodeRenderer.kt consumes these labels when rendering the final output, so changes to the provider immediately affect both inline citations and the reference list.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →