Component overrides
The generated pages are Astro components. Each one renders a normalised model of your package, and you can replace nine of them with your own components. Do this when you need different markup: an extra badge in every signature, or a warning above every abstract class. If you only want different colours or spacing, use Theming instead. Theming needs CSS and no components.
An override applies everywhere its component is used. This includes the generated pages, the
<Autodoc> blocks you embed in hand-written pages, and other
overrides.
Registering an override
Section titled “Registering an override”Name the component and point at a file. A value starting with ., or an absolute path, resolves
against the Astro project root. Any other value is passed through as a package specifier. This lets
an override ship from your own npm package.
starlightPydocs({ packages: [{ name: 'mypkg', search: ['../src'] }], components: { SourceLink: './src/components/pydocs/SourceLink.astro', Signature: '@internal/docs-theme/PySignature.astro', },});The components themselves can live anywhere in your project. This page keeps them together:
- astro.config.mjs
Directorysrc/
Directorycomponents/
Directorypydocs/
- ClassDoc.astro wraps the built-in renderer
- SourceLink.astro replaces it outright
- package.json
An unknown component name causes a configuration error, and the error message lists the nine valid names. This way, a typo fails the build instead of being ignored.
Wrapping the built-in component
Section titled “Wrapping the built-in component”The built-in components are exported from starlight-pydocs/components, so an override can add to
one rather than reimplement it. Importing the original there is safe. It bypasses the override
mechanism, so there is no loop.
A useful override often needs only three things: an import, the markup you add, and one line that hands the rest back. Here, the override adds a warning above every abstract class:
---import { ClassDoc } from 'starlight-pydocs/components';import type { RenderScope } from 'starlight-pydocs/render';
// `DocObject` is the shape of every documented object, reachable through the scope type.type DocObject = RenderScope['model']['root'];
interface Props { doc: DocObject; scope: RenderScope; labels?: Record<string, string> | undefined;}
const { doc, scope, labels } = Astro.props;const isAbstract = doc.labels.includes('abstract');---
{ isAbstract ? ( <aside class="pyd-aside pyd-aside--caution">Abstract: subclass it, do not instantiate it.</aside> ) : null}<ClassDoc doc={doc} scope={scope} labels={labels} />The last line hands everything else back to the built-in renderer, including labels. This keeps
the class bodies rendering exactly as they did before.
Overrides are compiled by your own project, so astro check covers them. Declare the props exactly
as listed below. Then the check is meaningful: an override with a missing prop fails at build time
instead of rendering a blank block.
The nine components
Section titled “The nine components”| Name | Renders | Props |
|---|---|---|
ModuleDoc |
A whole module page: docstring, member summary, submodule list, members | doc, scope, headingLevel?, labels? |
ClassDoc |
A class body: signature, bases, docstring sections | doc, scope, labels? |
FunctionDoc |
A function or method body: signature and docstring sections | doc, scope, labels? |
AttributeDoc |
An attribute or property body | doc, scope, labels? |
Signature |
The signature block, including @overload variants |
doc, scope, labels?, class? |
DocstringSections |
Every parsed docstring section, in docstring order | doc, scope, labels? |
MemberSummary |
The table of members at the top of a page or class | doc, scope, labels? |
SourceLink |
The View source link |
doc, labels? |
Heading |
An anchor heading with its permalink | level, id, class?, labels?, default slot |
Everything else is fixed. The object heading, badges, provenance line and deprecation notice come
from ObjectDoc, which also handles the recursion into members. <Autodoc> and <SymbolSearch>
are entry points, not pieces you can replace. Style those with CSS instead.
The props
Section titled “The props”doc is one documented object and scope is everything needed to render it. The doc fields you
are most likely to use:
doc field |
Meaning |
|---|---|
path, canonicalPath, name |
Documented path (also the heading id), definition path, short name |
kind |
module, class, function, attribute or alias |
labels |
Griffe’s labels: property, classmethod, pydantic-model, … |
summary, docstring |
First docstring line as plain text; the raw text plus parsed sections |
members, groups |
Filtered members, and the same members bucketed for rendering |
bases, mro, unresolvedBases |
Declared bases with resolution, the linearisation, what did not resolve |
inheritedFrom, reexportedFrom |
Provenance, when the object is not defined where it is documented |
deprecated |
{ version, description } when anything marks it deprecated |
source |
{ file, startLine, endLine, href } |
pageSlug |
The page the object is rendered on |
scope field |
Meaning |
|---|---|
context |
Site configuration: siteBase, trailingSlash, packages, the feature flags |
pkg |
The package being rendered |
model |
The whole normalised package: pages, objectsByPath, symbolsByPath, scopes |
resolver |
Annotation name resolver, wired to the site’s inventories |
rendered |
Pre-rendered docstring HTML, keyed by canonical path and section index |
labels is a StringOverrides object. You can pass it to any component to override individual
strings. Pass it down so overrides keep working through your component.
starlight-pydocs/render exports the helpers the built-in components use, so an override rarely has
to compute anything itself: hrefForPath, hrefForTarget, pageHref, packageAssetHref,
objectBadges, splitInherited, admonitionKind, admonitionTitle and createRenderScope.
Replacing a component outright
Section titled “Replacing a component outright”When the built-in markup is not the starting point you want, declare the same props and render
whatever you like. For example, make the View source link carry a forge icon and open in a new
tab:
---import type { RenderScope } from 'starlight-pydocs/render';
// `DocObject` is the shape of every documented object, reachable through the scope type.type DocObject = RenderScope['model']['root'];
interface Props { doc: DocObject; labels?: Record<string, string> | undefined;}
const { doc } = Astro.props;const source = doc.source;---
{ source?.href === undefined ? null : ( <a class="pyd-source-link" href={source.href} target="_blank" rel="noreferrer noopener"> <svg aria-hidden="true" width="14" height="14" viewBox="0 0 16 16"><path d="M8 0a8 8 0 0 0-2.5 15.6c.4.1.5-.2.5-.4v-1.4c-2.2.5-2.7-1-2.7-1-.4-1-.9-1.2-.9-1.2-.7-.5 0-.5 0-.5.8.1 1.2.8 1.2.8.7 1.2 1.9.9 2.4.7.1-.5.3-.9.5-1.1-1.8-.2-3.6-.9-3.6-4 0-.9.3-1.6.8-2.1-.1-.2-.4-1 .1-2.1 0 0 .7-.2 2.2.8a7.7 7.7 0 0 1 4 0c1.5-1 2.2-.8 2.2-.8.5 1.1.2 1.9.1 2.1.5.5.8 1.2.8 2.1 0 3.1-1.8 3.8-3.6 4 .4.3.7.9.7 1.8v2.6c0 .2.1.5.6.4A8 8 0 0 0 8 0Z" /></svg> {' '} Source </a> )}Register it under its component name:
starlightPydocs({ packages: [{ name: 'mypkg', search: ['../src'] }], components: { SourceLink: './src/components/pydocs/SourceLink.astro' },});Every object on every generated page, and every <Autodoc> block, now uses it.