diff --git a/config.public.mk b/config.public.mk
index ff16ec86..dcf10297 100644
--- a/config.public.mk
+++ b/config.public.mk
@@ -17,7 +17,7 @@ LINKML_SCHEMA_SOURCE_DIR="src/common_access_model/schema"
LINKML_GENERATORS_CONFIG_YAML=config.yaml
## pass args if gendoc ignores config.yaml (i.e. --no-mergeimports)
-LINKML_GENERATORS_DOC_ARGS=
+LINKML_GENERATORS_DOC_ARGS="--template-directory docs/templates-linkml"
## pass args to workaround genowl rdfs config bug (linkml#1453)
## (i.e. --no-type-objects --no-metaclasses --metadata-profile rdfs)
diff --git a/docs/templates-linkml/class.md.jinja2 b/docs/templates-linkml/class.md.jinja2
new file mode 100644
index 00000000..4d4e350c
--- /dev/null
+++ b/docs/templates-linkml/class.md.jinja2
@@ -0,0 +1,295 @@
+---
+search:
+ boost: {% if element.deprecated %}0.5{% else %}10.0{% endif %}
+---
+
+{%- if element.title %}
+ {%- set title = element.title ~ ' (' ~ element.name ~ ')' -%}
+{%- else %}
+ {%- if gen.use_class_uris -%}
+ {%- set title = element.name -%}
+ {%- else -%}
+ {%- set title = gen.name(element) -%}
+ {%- endif -%}
+{%- endif -%}
+
+{% macro compute_range(slot) -%}
+ {%- if slot.any_of or slot.exactly_one_of -%}
+ {%- set expr_ranges = (slot.exactly_one_of + slot.any_of) | selectattr('range') | map(attribute='range') | unique | list -%}
+ {%- if expr_ranges -%}
+ {%- for subslot_range in expr_ranges -%}
+ {{ gen.link(subslot_range) }}
+ {%- if not loop.last -%}
+ or
+ {%- endif -%}
+ {%- endfor -%}
+ {%- else -%}
+ {{ gen.link(slot.range) }}
+ {%- endif -%}
+ {%- else -%}
+ {{ gen.link(slot.range) }}
+ {%- endif -%}
+{% endmacro %}
+
+# Class: {{ title }} {% if element.deprecated %} (DEPRECATED) {% endif %}
+
+{%- if header -%}
+{{ header }}
+{%- endif -%}
+
+{% if element.description %}
+{% set element_description_lines = element.description.split('\n') %}
+{% for element_description_line in element_description_lines %}
+_{{ element_description_line }}_
+{% endfor %}
+{% endif %}
+
+
+
+{% if element.abstract %}
+* __NOTE__: this is an abstract class and should not be instantiated directly
+{% endif %}
+
+URI: {{ gen.uri_link(element) }}
+
+{% if diagram_type == "er_diagram" %}
+```{{ gen.mermaid_directive() }}
+{{ gen.mermaid_diagram([element.name]) }}
+```
+{% elif diagram_type == "plantuml_class_diagram" %}
+```puml
+{{ gen.mermaid_diagram([element.name]) }}
+```
+{% else %}
+{% include "class_diagram.md.jinja2" %}
+{% endif %}
+
+{% if schemaview.class_parents(element.name) or schemaview.class_children(element.name, mixins=False) %}
+
+## Inheritance
+{{ gen.inheritance_tree(element, mixins=True) }}
+{% else %}
+
+{% endif %}
+
+{%- set has_class_props = element.class_uri or element.tree_root or element.mixin
+ or element.subclass_of or element.union_of or element.disjoint_with
+ or element.slot_names_unique or element.represents_relationship
+ or element.children_are_mutually_disjoint %}
+
+{%- if has_class_props %}
+## Class Properties
+
+| Property | Value |
+| --- | --- |
+{%- if element.class_uri %}
+| Class URI | {{ gen.uri_link(element.class_uri) }} |
+{%- endif %}
+{%- if element.mixin %}
+| Mixin | Yes |
+{%- endif %}
+{%- if element.tree_root %}
+| Tree Root | Yes |
+{%- endif %}
+{%- if element.slot_names_unique %}
+| Slot Names Unique | Yes |
+{%- endif %}
+{%- if element.represents_relationship %}
+| Represents Relationship | Yes |
+{%- endif %}
+{%- if element.subclass_of %}
+| Subclass Of | {{ gen.links(element.subclass_of) | join(', ') }} |
+{%- endif %}
+{%- if element.union_of %}
+| Union Of | {{ gen.links(element.union_of) | join(', ') }} |
+{%- endif %}
+{%- if element.disjoint_with %}
+| Disjoint With | {{ gen.links(element.disjoint_with) | join(', ') }} |
+{%- endif %}
+{%- if element.children_are_mutually_disjoint %}
+| Children Are Mutually Disjoint | Yes |
+{%- endif %}
+
+{% endif %}
+## Slots
+
+| Name | Cardinality and Range | Description | Inheritance |
+| --- | --- | --- | --- |
+{% if gen.get_direct_slots(element)|length > 0 %}
+{%- for slot in gen.get_direct_slots(element) -%}
+| {{ gen.link(slot) }} | {{ gen.cardinality(slot) }}
{{ compute_range(slot) }} | {{ slot.description|enshorten }} | direct |
+{% endfor -%}
+{% endif -%}
+{% if gen.get_indirect_slots(element)|length > 0 %}
+{%- for slot in gen.get_indirect_slots(element) -%}
+| {{ gen.link(slot) }} | {{ gen.cardinality(slot) }}
{{ compute_range(slot) }} | {{ slot.description|enshorten }} | {{ gen.links(gen.get_slot_inherited_from(element.name, slot.name))|join(', ') }} |
+{% endfor -%}
+{% endif %}
+
+{%- if element.unique_keys %}
+## Unique Keys
+
+{% for uk in element.unique_keys.values() %}
+### {{ uk.unique_key_name }}
+
+**Unique key slots:** {{ uk.unique_key_slots | join(', ') }}
+{%- if uk.consider_nulls_inequal %}
+
+Considers null values as inequal
+{%- endif %}
+{% endfor %}
+{% endif %}
+
+{%- if element.defining_slots %}
+## Defining Slots
+
+This class is defined by the following slots:
+
+{% for slot_name in element.defining_slots %}
+* {{ gen.link(slot_name) }}
+{%- endfor %}
+{% endif %}
+
+{%- set has_expressions = element.any_of or element.all_of or element.exactly_one_of
+ or element.none_of or element.slot_conditions %}
+
+{%- if has_expressions %}
+
+Expressions & Logic
+
+{%- if element.any_of %}
+#### Any Of
+
+The class must satisfy at least one of:
+
+{%- for expr in element.any_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.all_of %}
+#### All Of
+
+The class must satisfy all of:
+
+{%- for expr in element.all_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.exactly_one_of %}
+#### Exactly One Of
+
+The class must satisfy exactly one of:
+
+{%- for expr in element.exactly_one_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.none_of %}
+#### None Of
+
+The class must not satisfy any of:
+
+{%- for expr in element.none_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.slot_conditions %}
+#### Slot Conditions
+
+{%- for slot_name, conditions in element.slot_conditions.items() %}
+- **{{ gen.link(slot_name) }}**: {{ conditions }}
+{%- endfor %}
+{%- endif %}
+
+
+{% endif %}
+
+{% if schemaview.is_mixin(element.name) %}
+## Mixin Usage
+
+| mixed into | description |
+| --- | --- |
+{% for c in schemaview.class_children(element.name, is_a=False) -%}
+| {{ gen.link(c) }} | {{ schemaview.get_class(c).description|enshorten }} |
+{% endfor %}
+{% endif %}
+
+{% if schemaview.usage_index().get(element.name) %}
+## Usages
+
+| used by | used in | type | used |
+| --- | --- | --- | --- |
+{% for usage in schemaview.usage_index().get(element.name) -%}
+| {{ gen.link(usage.used_by) }} | {{ gen.link(usage.slot) }} | {{ usage.metaslot }} | {{ gen.link(usage.used) }} |
+{% endfor %}
+{% endif %}
+
+{% if element.rules %}
+## Rules
+
+{% for rule in gen.classrule_to_dict_view(element) %}
+### {{ rule.title }}
+
+| Rule Applied | Preconditions | Postconditions | Elseconditions |
+|--------------|---------------|----------------|----------------|
+{% for key in rule.preconditions|default({}) -%}
+| {{ key }} |
+{%- if rule.preconditions[key] is defined -%}
+```{{ rule.preconditions[key] }}```
+{%- else -%}
+{% endif %} |
+{%- if rule.postconditions and rule.postconditions[key] is defined -%}
+```{{ rule.postconditions[key] }}```
+{%- else -%}
+{% endif %} |
+{%- if rule.elseconditions and rule.elseconditions[key] is defined -%}
+```{{ rule.elseconditions[key] }}```
+{%- else -%}
+{% endif %} |
+{% endfor %}
+
+{% endfor %}
+{% endif %}
+
+{% include "common_metadata.md.jinja2" %}
+
+{% if gen.example_object_blobs(element.name) -%}
+## Examples
+{% for name, blob in gen.example_object_blobs(element.name) -%}
+### Example: {{ name }}
+
+```yaml
+{{ blob }}
+```
+{% endfor %}
+{% endif %}
+
+## LinkML Source
+
+
+
+### Direct
+
+
+```yaml
+{{ gen.yaml(element) }}
+```
+
+
+### Induced
+
+
+```yaml
+{{ gen.yaml(element, inferred=True) }}
+```
+
+
+{%- if footer -%}
+{{ footer }}
+{%- endif -%}
+
+
diff --git a/docs/templates-linkml/class_diagram.md.jinja2 b/docs/templates-linkml/class_diagram.md.jinja2
new file mode 100644
index 00000000..95c2e980
--- /dev/null
+++ b/docs/templates-linkml/class_diagram.md.jinja2
@@ -0,0 +1,76 @@
+{% macro slot_relationship(element, slot) %}
+ {% if slot.range is not none %}
+ {% set range_element = gen.name(schemaview.get_element(slot.range)) %}
+ {% set relation_label = gen.name(slot) %}
+ {{ gen.name(element) }} --> "{{ gen.cardinality(slot) }}" {{ range_element }} : {{ relation_label }}
+ click {{ range_element }} href "{{ gen.link_mermaid(schemaview.get_element(slot.range)) }}"
+ {% endif %}
+{% endmacro %}
+
+{% if schemaview.class_parents(element.name) and schemaview.class_children(element.name) %}
+```{{ gen.mermaid_directive() }}
+ classDiagram
+ class {{ gen.name(element) }}
+ click {{ gen.name(element) }} href "{{ gen.link_mermaid(element) }}"
+ {% for s in schemaview.class_parents(element.name)|sort(attribute='name') -%}
+ {{ gen.name(schemaview.get_element(s)) }} <|-- {{ gen.name(element) }}
+ click {{ gen.name(schemaview.get_element(s)) }} href "{{ gen.link_mermaid(schemaview.get_element(s)) }}"
+ {% endfor %}
+
+ {% for s in schemaview.class_children(element.name)|sort(attribute='name') -%}
+ {{ gen.name(element) }} <|-- {{ gen.name(schemaview.get_element(s)) }}
+ click {{ gen.name(schemaview.get_element(s)) }} href "{{ gen.link_mermaid(schemaview.get_element(s)) }}"
+ {% endfor %}
+
+ {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
+ {{ gen.name(element) }} : {{ gen.name(s) }}
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
+ {{ slot_relationship(element, s) }}
+ {% endif %}
+ {% endfor %}
+```
+{% elif schemaview.class_parents(element.name) %}
+```{{ gen.mermaid_directive() }}
+ classDiagram
+ class {{ gen.name(element) }}
+ click {{ gen.name(element) }} href "{{ gen.link_mermaid(element) }}"
+ {% for s in schemaview.class_parents(element.name)|sort(attribute='name') -%}
+ {{ gen.name(schemaview.get_element(s)) }} <|-- {{ gen.name(element) }}
+ click {{ gen.name(schemaview.get_element(s)) }} href "{{ gen.link_mermaid(schemaview.get_element(s)) }}"
+ {% endfor %}
+ {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
+ {{ gen.name(element) }} : {{ gen.name(s) }}
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
+ {{ slot_relationship(element, s) }}
+ {% endif %}
+ {% endfor %}
+```
+{% elif schemaview.class_children(element.name) %}
+```{{ gen.mermaid_directive() }}
+ classDiagram
+ class {{ gen.name(element) }}
+ click {{ gen.name(element) }} href "{{ gen.link_mermaid(element) }}"
+ {% for s in schemaview.class_children(element.name)|sort(attribute='name') -%}
+ {{ gen.name(element) }} <|-- {{ gen.name(schemaview.get_element(s)) }}
+ click {{ gen.name(schemaview.get_element(s)) }} href "{{ gen.link_mermaid(schemaview.get_element(s)) }}"
+ {% endfor %}
+ {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
+ {{ gen.name(element) }} : {{ gen.name(s) }}
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
+ {{ slot_relationship(element, s) }}
+ {% endif %}
+ {% endfor %}
+```
+{% else %}
+```{{ gen.mermaid_directive() }}
+ classDiagram
+ class {{ gen.name(element) }}
+ click {{ gen.name(element) }} href "{{ gen.link_mermaid(element) }}"
+ {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
+ {{ gen.name(element) }} : {{ gen.name(s) }}
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
+ {{ slot_relationship(element, s) }}
+ {% endif %}
+ {% endfor %}
+```
+{% endif %}
diff --git a/docs/templates-linkml/common_metadata.md.jinja2 b/docs/templates-linkml/common_metadata.md.jinja2
new file mode 100644
index 00000000..cdc0598f
--- /dev/null
+++ b/docs/templates-linkml/common_metadata.md.jinja2
@@ -0,0 +1,142 @@
+{% if element.categories %}
+## Categories
+
+{% for cat in element.categories %}
+* {{ cat }}
+{%- endfor %}
+
+{% endif %}
+{% if element.keywords %}
+## Keywords
+
+{% for kw in element.keywords %}
+* {{ kw }}
+{%- endfor %}
+
+{% endif %}
+{% if element.in_subset %}
+## In Subsets
+
+{% for subset in element.in_subset %}
+* {{ gen.link(subset) }}
+{%- endfor %}
+
+{% endif %}
+{% if element.aliases %}
+## Aliases
+
+{% for alias in element.aliases %}
+* {{ alias }}
+{%- endfor %}
+{% endif %}
+
+{% if element.examples %}
+## Examples
+
+| Value |
+| --- |
+{% for x in element.examples -%}
+| {{ x.value }} |
+{% endfor %}
+{% endif -%}
+
+{% if element.comments -%}
+## Comments
+
+{% for x in element.comments -%}
+* {{ x }}
+{% endfor %}
+{% endif -%}
+
+{% if element.todos -%}
+## TODOs
+
+{% for x in element.todos -%}
+* {{ x }}
+{% endfor %}
+{% endif -%}
+
+{% if element.see_also -%}
+## See Also
+
+{% for x in element.see_also -%}
+* {{ gen.uri_link(x) }}
+{% endfor %}
+{% endif -%}
+
+{% if element.notes -%}
+## Notes
+
+{% for note in element.notes -%}
+* {{ note }}
+{% endfor %}
+{% endif -%}
+
+{% if element.alt_descriptions %}
+## Alternative Descriptions
+
+{% for source, alt_desc in element.alt_descriptions.items() %}
+* **{{ source }}**: {{ alt_desc.description }}
+{%- endfor %}
+{% endif %}
+
+## Identifier and Mapping Information
+
+{%- set has_admin_metadata = element.status or (element.rank is not none and element.rank != 1000) %}
+
+{%- if has_admin_metadata %}
+### Administrative Metadata
+
+{% if element.status -%}
+**Status:** {{ element.status }}
+{% endif -%}
+{% if element.rank is not none and element.rank != 1000 -%}
+**Rank:** {{ element.rank }}
+{% endif -%}
+
+{% endif %}
+{% if element.id_prefixes %}
+### Valid ID Prefixes
+
+Instances of this class *should* have identifiers with one of the following prefixes:
+{% for p in element.id_prefixes %}
+* {{ p }}
+{% endfor %}
+
+{% endif %}
+
+{% if element.annotations %}
+### Annotations
+
+| property | value |
+| --- | --- |
+{% for a in element.annotations -%}
+{%- if a|string|first != '_' -%}
+| {{ a }} | {{ element.annotations[a].value }} |
+{% endif -%}
+{% endfor %}
+{% endif %}
+
+{% if element.from_schema or element.imported_from %}
+### Schema Source
+
+{% if element.from_schema %}
+* from schema: {{ element.from_schema }}
+{% endif %}
+{% if element.imported_from %}
+* imported from: {{ element.imported_from }}
+{% endif %}
+{% endif %}
+
+{% if schemaview.get_mappings(element.name).items() -%}
+## Mappings
+
+| Mapping Type | Mapped Value |
+| --- | --- |
+{% for m, mt in schemaview.get_mappings(element.name).items() -%}
+{% if mt|length > 0 -%}
+| {{ m }} | {{ mt|join(', ') }} |
+{% endif -%}
+{% endfor %}
+
+{% endif -%}
diff --git a/docs/templates-linkml/enum.md.jinja2 b/docs/templates-linkml/enum.md.jinja2
new file mode 100644
index 00000000..07ccd5b5
--- /dev/null
+++ b/docs/templates-linkml/enum.md.jinja2
@@ -0,0 +1,203 @@
+---
+search:
+ boost: {% if element.deprecated %}0.5{% else %}2.0{% endif %}
+---
+
+{%- if element.title and element.title != element.name %}
+ {%- set title = element.title ~ ' (' ~ element.name ~ ')' -%}
+{%- else %}
+ {%- set title = gen.name(element) -%}
+{%- endif -%}
+
+{# Render an EnumExpression / AnonymousEnumExpression as a Markdown sub-list.
+ Walks the selector slots defined on `enum_expression` in the LinkML metamodel
+ (reachable_from, concepts, code_set, matches, pv_formula, inherits) and
+ formats each as a top-level bullet with any modifier fields nested below. #}
+{% macro render_enum_expression(expr) -%}
+{%- if expr.reachable_from %}
+- **Reachable from**{% if expr.reachable_from.source_ontology %} {{ gen.uri_link(expr.reachable_from.source_ontology) }}{% endif %}
+{%- if expr.reachable_from.source_nodes %}
+ - Source nodes: {{ expr.reachable_from.source_nodes | join(', ') }}
+{%- endif %}
+{%- if expr.reachable_from.relationship_types %}
+ - Via relationships: {{ expr.reachable_from.relationship_types | join(', ') }}
+{%- endif %}
+{%- if expr.reachable_from.is_direct %}
+ - Direct descendants only
+{%- endif %}
+{%- if expr.reachable_from.include_self %}
+ - Includes the source node itself
+{%- endif %}
+{%- if expr.reachable_from.traverse_up %}
+ - Traverses upward (ancestors)
+{%- endif %}
+{%- endif %}
+{%- if expr.concepts %}
+- **Concepts:** {{ expr.concepts | join(', ') }}
+{%- endif %}
+{%- if expr.code_set %}
+- **Code set:** {{ gen.uri_link(expr.code_set) }}
+{%- if expr.code_set_tag %}
+ - Tag: {{ expr.code_set_tag }}
+{%- endif %}
+{%- if expr.code_set_version %}
+ - Version: {{ expr.code_set_version }}
+{%- endif %}
+{%- endif %}
+{%- if expr.matches %}
+- **Matches identifier pattern** `{{ expr.matches.identifier_pattern }}`
+{%- if expr.matches.source_ontology %}
+ - Source ontology: {{ gen.uri_link(expr.matches.source_ontology) }}
+{%- endif %}
+{%- endif %}
+{%- if expr.pv_formula %}
+- **Permissible value formula:** {{ expr.pv_formula }}
+{%- endif %}
+{%- if expr.inherits %}
+- **Inherits from:** {{ gen.links(expr.inherits) | join(', ') }}
+{%- endif %}
+{% endmacro %}
+
+# Enum: {{ title }} {% if element.deprecated %} (DEPRECATED) {% endif %}
+
+{% if element.description %}
+{% set element_description_lines = element.description.split('\n') %}
+{% for element_description_line in element_description_lines %}
+_{{ element_description_line }}_
+{% endfor %}
+{% endif %}
+
+
+
+URI: {{ gen.uri_link(element) }}
+
+{%- if element.enum_uri %}
+
+**Enum URI:** {{ gen.uri_link(element.enum_uri) }}
+{% endif %}
+
+{%- set has_enum_source = element.code_set or element.pv_formula or element.reachable_from
+ or element.matches or element.concepts %}
+
+{%- if has_enum_source %}
+## Enumeration Source
+
+{%- if element.code_set %}
+**Code Set:** {{ gen.uri_link(element.code_set) }}
+
+{%- if element.code_set_tag %}
+- **Tag:** {{ element.code_set_tag }}
+{%- endif %}
+{%- if element.code_set_version %}
+- **Version:** {{ element.code_set_version }}
+{%- endif %}
+{%- endif %}
+
+{%- if element.pv_formula %}
+**Permissible Value Formula:** {{ element.pv_formula }}
+{%- endif %}
+
+{%- if element.reachable_from %}
+**Reachable From:**
+
+{%- if element.reachable_from.source_ontology %}
+- **Source:** {{ gen.link(element.reachable_from.source_ontology) }}
+{%- endif %}
+{%- if element.reachable_from.source_nodes %}
+- **Nodes:** {{ element.reachable_from.source_nodes | join(', ') }}
+{%- endif %}
+{%- if element.reachable_from.relationship_types %}
+- **Via:** {{ element.reachable_from.relationship_types | join(', ') }}
+{%- endif %}
+{%- endif %}
+
+{%- if element.matches %}
+**Matches:**
+
+- **Expression:** `{{ element.matches.string_expression }}`
+{%- endif %}
+
+{%- if element.concepts %}
+**Concepts:** {{ gen.uri_links(element.concepts) | join(', ') }}
+{%- endif %}
+
+{% endif %}
+
+{% if element.permissible_values -%}
+{%- set has_pv_extras = namespace(found=false) -%}
+{%- for pv in element.permissible_values.values() -%}
+ {%- if pv.title or pv.is_a or pv.mixins or pv.deprecated -%}
+ {%- set has_pv_extras.found = true -%}
+ {%- endif -%}
+{%- endfor -%}
+## Permissible Values
+
+{%- if has_pv_extras.found %}
+| Value | Meaning | Description | Additional Info |
+| --- | --- | --- | --- |
+{% for pv in element.permissible_values.values() -%}
+| {{ pv.text }} | {{ pv.meaning }} | {{ pv.description|enshorten }} |
+{%- if pv.title %} Title: {{ pv.title }}
{% endif -%}
+{%- if pv.is_a %} Is-A: {{ gen.link(pv.is_a) }}
{% endif -%}
+{%- if pv.mixins %} Mixins: {{ gen.links(pv.mixins) | join(', ') }}
{% endif -%}
+{%- if pv.deprecated %} **DEPRECATED**{% if pv.deprecated_element_has_exact_replacement %} (use {{ gen.link(pv.deprecated_element_has_exact_replacement) }}){% endif %}{% endif -%}
+ |
+{% endfor %}
+{%- else %}
+| Value | Meaning | Description |
+| --- | --- | --- |
+{% for pv in element.permissible_values.values() -%}
+| {{ pv.text }} | {{ pv.meaning }} | {{ pv.description|enshorten }} |
+{% endfor %}
+{%- endif %}
+{% else %}
+_This is a dynamic enum_
+{% endif %}
+
+{%- set has_enum_ops = element.inherits or element.include or element.minus %}
+
+{%- if has_enum_ops %}
+## Enumeration Operations
+
+{%- if element.inherits %}
+**Inherits From:** {{ gen.links(element.inherits) | join(', ') }}
+{%- endif %}
+
+{%- if element.include %}
+**Includes:**
+{% for expr in element.include -%}
+{{ render_enum_expression(expr) }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.minus %}
+**Excludes:**
+{% for expr in element.minus -%}
+{{ render_enum_expression(expr) }}
+{%- endfor %}
+{%- endif %}
+
+{% endif %}
+
+{% set slots_for_enum = schemaview.get_slots_by_enum(element.name) %}
+{% if slots_for_enum is defined and slots_for_enum|length > 0 -%}
+## Slots
+
+| Name | Description |
+| --- | --- |
+{% for s in schemaview.get_slots_by_enum(element.name) -%}
+| {{ gen.link(s) }} | {{ s.description|enshorten }} |
+{% endfor %}
+{% endif %}
+
+{% include "common_metadata.md.jinja2" %}
+
+## LinkML Source
+
+
+```yaml
+{{ gen.yaml(element) }}
+```
+
+
+
diff --git a/docs/templates-linkml/index.md.jinja2 b/docs/templates-linkml/index.md.jinja2
new file mode 100644
index 00000000..fe14498e
--- /dev/null
+++ b/docs/templates-linkml/index.md.jinja2
@@ -0,0 +1,62 @@
+# {% if schema.title %}{{ schema.title }}{% else %}{{ schema.name }}{% endif %}
+
+{% if schema.description %}{{ schema.description }}{% endif %}
+
+URI: {{ schema.id }}
+
+Name: {{ schema.name }}
+
+{% if include_top_level_diagram %}
+
+## Schema Diagram
+
+```{{ gen.mermaid_directive() }}
+{{ gen.mermaid_diagram() }}
+```
+{% endif %}
+
+## Classes
+
+| Class | Description |
+| --- | --- |
+{% if gen.hierarchical_class_view -%}
+{% for u, v in gen.class_hierarchy_as_tuples() -%}
+| {{ " "|safe*u*8 }}{{ gen.link(schemaview.get_class(v), True) }} | {{ schemaview.get_class(v).description|enshorten }} |
+{% endfor %}
+{% else -%}
+{% for c in gen.all_class_objects()|sort(attribute=sort_by) -%}
+| {{ gen.link(c, True) }} | {{ c.description|enshorten }} |
+{% endfor %}
+{% endif %}
+
+## Slots
+
+| Slot | Description |
+| --- | --- |
+{% for s in gen.all_slot_objects()|sort(attribute=sort_by) -%}
+| {{ gen.link(s, True) }} | {{ s.description|enshorten }} |
+{% endfor %}
+
+## Enumerations
+
+| Enumeration | Description |
+| --- | --- |
+{% for e in gen.all_enum_objects()|sort(attribute=sort_by) -%}
+| {{ gen.link(e, True) }} | {{ e.description|enshorten }} |
+{% endfor %}
+
+## Types
+
+| Type | Description |
+| --- | --- |
+{% for t in gen.all_type_objects()|sort(attribute=sort_by) -%}
+| {{ gen.link(t, True) }} | {{ t.description|enshorten }} |
+{% endfor %}
+
+## Subsets
+
+| Subset | Description |
+| --- | --- |
+{% for ss in schemaview.all_subsets().values()|sort(attribute='name') -%}
+| {{ gen.link(ss, True) }} | {{ ss.description|enshorten }} |
+{% endfor %}
diff --git a/docs/templates-linkml/index.tex.jinja2 b/docs/templates-linkml/index.tex.jinja2
new file mode 100644
index 00000000..782b712b
--- /dev/null
+++ b/docs/templates-linkml/index.tex.jinja2
@@ -0,0 +1,26 @@
+\documentclass{article}
+\usepackage[utf8]{inputenc}
+
+\title{ {{ gen.latex(gen.schema_title()) }} }
+
+\begin{document}
+
+{{ schema.description }}
+
+URI: {{ gen.latex(schema.id) }}
+Name: {{ gen.latex(schema.name) }}
+
+\subsection{Classes}\label{classes}
+
+\begin{tabular}{ |c|c| }
+ \hline
+ Class & Description \\\\
+ \hline
+
+{% for c in schemaview.all_classes().values()|sort(attribute='name') -%}
+{{ gen.latex(c.name) }} & {{ gen.latex(c.description) }} \\\\
+{% endfor %}
+ \hline
+\end{tabular}
+
+\end{document}
diff --git a/docs/templates-linkml/schema.md.jinja2 b/docs/templates-linkml/schema.md.jinja2
new file mode 100644
index 00000000..847c58b0
--- /dev/null
+++ b/docs/templates-linkml/schema.md.jinja2
@@ -0,0 +1,5 @@
+# {{ schema.name }} {% if schema.deprecated %} (DEPRECATED) {% endif %}
+
+{{ schema.description }}
+
+URI: {{ schema.id }}
diff --git a/docs/templates-linkml/slot.md.jinja2 b/docs/templates-linkml/slot.md.jinja2
new file mode 100644
index 00000000..039a6102
--- /dev/null
+++ b/docs/templates-linkml/slot.md.jinja2
@@ -0,0 +1,534 @@
+---
+search:
+ boost: {% if element.deprecated %}0.5{% else %}5.0{% endif %}
+---
+
+{%- if element.title %}
+ {%- set title = element.title ~ ' (' ~ element.name ~ ')' -%}
+{%- else %}
+ {%- if gen.use_slot_uris -%}
+ {%- set title = element.name -%}
+ {%- else -%}
+ {%- set title = gen.name(element) -%}
+ {%- endif -%}
+{%- endif -%}
+
+{% macro compute_range(slot) -%}
+ {%- if slot.any_of or slot.exactly_one_of -%}
+ {%- set expr_ranges = (slot.exactly_one_of + slot.any_of) | selectattr('range') | map(attribute='range') | unique | list -%}
+ {%- if expr_ranges -%}
+ {%- for subslot_range in expr_ranges -%}
+ {{ gen.link(subslot_range) }}
+ {%- if not loop.last -%}
+ or
+ {%- endif -%}
+ {%- endfor -%}
+ {%- else -%}
+ {{ gen.link(slot.range) }}
+ {%- endif -%}
+ {%- else -%}
+ {{ gen.link(slot.range) }}
+ {%- endif -%}
+{% endmacro %}
+
+{% macro expr_line(expr) -%}
+{%- if expr.range %}{{ gen.link(expr.range) }}{% endif -%}
+{%- if expr.pattern %} matching pattern `{{ expr.pattern }}`{% endif -%}
+{%- if expr.minimum_value is not none %}, minimum {{ expr.minimum_value }}{% endif -%}
+{%- if expr.maximum_value is not none %}, maximum {{ expr.maximum_value }}{% endif -%}
+{%- if expr.equals_string %}, must equal `{{ expr.equals_string }}`{% endif -%}
+{%- if expr.equals_string_in %}, must be one of {{ expr.equals_string_in | join(', ') }}{% endif -%}
+{%- if expr.equals_number %}, must equal {{ expr.equals_number }}{% endif -%}
+{% endmacro %}
+
+# Slot: {{ title }} {% if element.deprecated %} (DEPRECATED) {% endif %}
+
+{%- if header -%}
+{{ header }}
+{%- endif -%}
+
+{% if element.description %}
+{% set element_description_lines = element.description.split('\n') %}
+{% for element_description_line in element_description_lines %}
+_{{ element_description_line }}_
+{% endfor %}
+{% endif %}
+
+
+
+{% if element.abstract %}
+* __NOTE__: this is an abstract slot and should not be populated directly
+{% endif %}
+
+URI: {{ gen.uri_link(element) }}
+
+{%- if element.alias %}
+Alias: {{ element.alias }}
+{% endif -%}
+
+{% if schemaview.slot_parents(element.name) or schemaview.slot_children(element.name, mixins=False) %}
+
+## Inheritance
+
+{{ gen.inheritance_tree(element, mixins=True) }}
+{% else %}
+
+{% endif %}
+
+{% set classes_by_slot = schemaview.get_classes_by_slot(element, include_induced=True) %}
+{% if classes_by_slot %}
+
+## Applicable Classes
+
+| Name | Description | Modifies Slot |
+| --- | --- | --- |
+{% for c in classes_by_slot -%}
+| {{ gen.link(c) }} | {{ schemaview.get_class(c).description|enshorten }} | {% if c in schemaview.get_classes_modifying_slot(element) %} yes {% else %} no {% endif %} |
+{% endfor %}
+
+{% endif %}
+
+{% if schemaview.is_mixin(element.name) %}
+## Mixin Usage
+
+| mixed into | description | range | domain |
+| --- | --- | --- | --- |
+{% for s in schemaview.slot_children(element.name, is_a=False) -%}
+| {{ gen.link(s) }} | {{ schemaview.get_slot(s).description|enshorten }} | {{ schemaview.get_slot(s).range }} | {{ schemaview.get_classes_by_slot(schemaview.get_slot(s))|join(', ') }} |
+{% endfor %}
+{% endif %}
+
+## Properties
+
+### Type and Range
+
+| Property | Value |
+| --- | --- |
+| Range | {{ compute_range(element) }} |
+{%- if element.domain %}
+| Domain | {{ gen.link(element.domain) }} |
+{%- endif %}
+{%- if element.domain_of %}
+| Domain Of | {{ gen.links(element.domain_of) | join(', ') }} |
+{%- endif %}
+{%- if element.slot_uri %}
+| Slot URI | {{ gen.uri_link(element.slot_uri) }} |
+{%- endif %}
+{%- if element.slot_group %}
+| Slot Group | {{ gen.link(element.slot_group) }} |
+{%- endif %}
+{%- if element.is_grouping_slot %}
+| Is Grouping Slot | Yes |
+{%- endif %}
+
+### Cardinality and Requirements
+
+| Property | Value |
+| --- | --- |
+{%- if element.required %}
+| Required | Yes |
+{%- elif element.recommended %}
+| Recommended | Yes |
+{%- endif %}
+{%- if element.multivalued %}
+| Multivalued | Yes |
+{%- endif %}
+{%- if element.minimum_cardinality is not none %}
+| Minimum Cardinality | {{ element.minimum_cardinality }} |
+{%- endif %}
+{%- if element.maximum_cardinality is not none %}
+| Maximum Cardinality | {{ element.maximum_cardinality }} |
+{%- endif %}
+{%- if element.exact_cardinality is not none %}
+| Exact Cardinality | {{ element.exact_cardinality }} |
+{%- endif %}
+
+{%- if element.multivalued and (element.list_elements_unique is not none or element.list_elements_ordered is not none) %}
+### List/Collection Properties
+
+| Property | Value |
+| --- | --- |
+{%- if element.list_elements_unique is not none %}
+| Elements Must Be Unique | {% if element.list_elements_unique %}Yes{% else %}No{% endif %} |
+{%- endif %}
+{%- if element.list_elements_ordered is not none %}
+| Elements Are Ordered | {% if element.list_elements_ordered %}Yes{% else %}No{% endif %} |
+{%- endif %}
+
+{% endif %}
+{%- set has_slot_chars = element.key or element.identifier or element.designates_type
+ or element.inherited or element.readonly or element.ifabsent or element.owner
+ or element.shared or element.is_class_field or element.is_usage_slot
+ or element.usage_slot_name or element.singular_name or schemaview.is_mixin(element.name) %}
+
+{%- if has_slot_chars %}
+### Slot Characteristics
+
+| Property | Value |
+| --- | --- |
+{%- if element.singular_name %}
+| Singular Name | {{ element.singular_name }} |
+{%- endif %}
+{%- if element.key %}
+| Key | Yes |
+{%- endif %}
+{%- if element.identifier %}
+| Identifier | Yes |
+{%- endif %}
+{%- if element.designates_type %}
+| Designates Type | Yes |
+{%- endif %}
+{%- if element.inherited %}
+| Inherited | Yes |
+{%- endif %}
+{%- if element.readonly %}
+| Readonly | Yes |
+{%- endif %}
+{%- if element.ifabsent %}
+| If Absent | `{{ element.ifabsent }}` |
+{%- endif %}
+{%- if element.owner %}
+| Owner | {{ gen.link(element.owner) }} |
+{%- endif %}
+{%- if element.shared %}
+| Shared | Yes |
+{%- endif %}
+{%- if element.is_class_field %}
+| Is Class Field | Yes |
+{%- endif %}
+{%- if element.is_usage_slot %}
+| Is Usage Slot | Yes |
+{%- endif %}
+{%- if element.usage_slot_name %}
+| Usage Slot Name | {{ element.usage_slot_name }} |
+{%- endif %}
+{%- if schemaview.is_mixin(element.name) %}
+| Mixin | Yes |
+{%- endif %}
+
+{% endif %}
+{%- set has_basic_constraints = element.minimum_value is not none or element.maximum_value is not none or element.pattern %}
+
+{%- if has_basic_constraints %}
+### Value Constraints
+
+| Property | Value |
+| --- | --- |
+{%- if element.minimum_value is not none %}
+| Minimum Value | {{ element.minimum_value|int }} |
+{%- endif %}
+{%- if element.maximum_value is not none %}
+| Maximum Value | {{ element.maximum_value|int }} |
+{%- endif %}
+{%- if element.pattern %}
+| Regex Pattern | `{{ element.pattern }}` |
+{%- endif %}
+
+{% endif %}
+{%- set has_advanced_constraints = element.structured_pattern or element.equals_string
+ or element.equals_string_in or element.equals_number or element.enum_range
+ or element.unit or element.implicit_prefix %}
+
+{%- if has_advanced_constraints %}
+
+Additional Constraints
+
+{%- if element.structured_pattern %}
+**Structured Pattern:**
+
+- **Syntax:** `{{ element.structured_pattern.syntax }}`
+- **Interpolated:** {{ element.structured_pattern.interpolated }}
+{%- if element.structured_pattern.partial_match %}
+- **Partial Match:** Yes
+{%- endif %}
+{%- endif %}
+
+{%- if element.equals_string %}
+**Must Equal:** `{{ element.equals_string }}`
+{%- endif %}
+
+{%- if element.equals_string_in %}
+**Must Be One Of:** {{ element.equals_string_in | join(', ') }}
+{%- endif %}
+
+{%- if element.equals_number %}
+**Must Equal:** {{ element.equals_number }}
+{%- endif %}
+
+{%- if element.enum_range %}
+**Enumeration Range:** {{ gen.link(element.enum_range) }}
+{%- endif %}
+
+{%- if element.unit %}
+**Unit:**
+
+| Property | Value |
+| --- | --- |
+{%- if element.unit.symbol %}
+| symbol | {{ element.unit.symbol }} |
+{%- endif %}
+{%- if element.unit.abbreviation %}
+| abbreviation | {{ element.unit.abbreviation }} |
+{%- endif %}
+{%- if element.unit.descriptive_name %}
+| descriptive_name | {{ element.unit.descriptive_name }} |
+{%- endif %}
+{%- if element.unit.ucum_code %}
+| ucum_code | {{ element.unit.ucum_code }} |
+{%- endif %}
+{%- if element.unit.derivation %}
+| derivation | {{ element.unit.derivation }} |
+{%- endif %}
+{%- if element.unit.iec61360code %}
+| iec61360code | {{ element.unit.iec61360code }} |
+{%- endif %}
+{%- if element.unit.has_quantity_kind %}
+| has_quantity_kind | {{ gen.uri_link(element.unit.has_quantity_kind) }} |
+{%- endif %}
+{%- if element.unit.exact_mappings %}
+| exact_mappings | {% for m in element.unit.exact_mappings %}{{ gen.uri_link(m) }}{% if not loop.last %}, {% endif %}{% endfor %} |
+{%- endif %}
+{%- endif %}
+
+{%- if element.implicit_prefix %}
+**Implicit Prefix:** {{ element.implicit_prefix }}
+{%- endif %}
+
+
+{% endif %}
+
+{%- set has_rel_props = element.symmetric or element.asymmetric or element.reflexive
+ or element.locally_reflexive or element.irreflexive or element.transitive
+ or element.inverse or element.transitive_form_of or element.reflexive_transitive_form_of
+ or element.role or element.relational_role %}
+
+{%- if has_rel_props %}
+
+Relationship Properties
+
+| Property | Value |
+| --- | --- |
+{%- if element.symmetric %}
+| Symmetric | Yes |
+{%- endif %}
+{%- if element.asymmetric %}
+| Asymmetric | Yes |
+{%- endif %}
+{%- if element.reflexive %}
+| Reflexive | Yes |
+{%- endif %}
+{%- if element.locally_reflexive %}
+| Locally Reflexive | Yes |
+{%- endif %}
+{%- if element.irreflexive %}
+| Irreflexive | Yes |
+{%- endif %}
+{%- if element.transitive %}
+| Transitive | Yes |
+{%- endif %}
+{%- if element.inverse %}
+| Inverse | {{ gen.link(element.inverse) }} |
+{%- endif %}
+{%- if element.transitive_form_of %}
+| Transitive Form Of | {{ gen.link(element.transitive_form_of) }} |
+{%- endif %}
+{%- if element.reflexive_transitive_form_of %}
+| Reflexive Transitive Form Of | {{ gen.link(element.reflexive_transitive_form_of) }} |
+{%- endif %}
+{%- if element.role %}
+| Role | {{ element.role }} |
+{%- endif %}
+{%- if element.relational_role %}
+| Relational Role | {{ element.relational_role }} |
+{%- endif %}
+
+
+{% endif %}
+
+{%- set has_advanced = element.path_rule or element.disjoint_with
+ or element.children_are_mutually_disjoint or element.subproperty_of
+ or element.array or element.bindings or element.type_mappings
+ or element.value_presence or element.range_expression %}
+
+{%- if has_advanced %}
+
+Advanced Properties
+
+{%- if element.subproperty_of %}
+**Subproperty Of:** {{ gen.link(element.subproperty_of) }}
+{%- endif %}
+
+{%- if element.path_rule %}
+**Path Rule:**
+
+```
+{{ element.path_rule }}
+```
+{%- endif %}
+
+{%- if element.disjoint_with %}
+**Disjoint With:** {{ gen.links(element.disjoint_with) | join(', ') }}
+{%- endif %}
+
+{%- if element.children_are_mutually_disjoint %}
+**Children Are Mutually Disjoint:** Yes
+{%- endif %}
+
+{%- if element.array %}
+**Array Configuration:**
+
+- **Dimensions:** {{ element.array.dimensions | join(' x ') }}
+{%- if element.array.exact_number_dimensions %}
+- **Exact Dimensions Required:** Yes
+{%- endif %}
+{%- endif %}
+
+{%- if element.range_expression %}
+**Range Expression:** {{ element.range_expression }}
+{%- endif %}
+
+{%- if element.value_presence %}
+**Value Presence:** {{ element.value_presence }}
+{%- endif %}
+
+{%- if element.bindings %}
+**Term Bindings:**
+
+{%- for binding in element.bindings %}
+- {{ binding }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.type_mappings %}
+**Type Mappings:**
+
+{%- for tm in element.type_mappings %}
+- **Framework:** {{ tm.framework }}, **Mapping:** {{ tm.mapping }}
+{%- endfor %}
+{%- endif %}
+
+
+{% endif %}
+
+{%- set any_of_has_extra = element.any_of | selectattr('pattern') | list
+ or element.any_of | selectattr('minimum_value') | list
+ or element.any_of | selectattr('maximum_value') | list
+ or element.any_of | selectattr('equals_string') | list
+ or element.any_of | selectattr('equals_string_in') | list
+ or element.any_of | selectattr('equals_number') | list %}
+
+{%- set all_of_has_extra = element.all_of | selectattr('pattern') | list
+ or element.all_of | selectattr('minimum_value') | list
+ or element.all_of | selectattr('maximum_value') | list
+ or element.all_of | selectattr('equals_string') | list
+ or element.all_of | selectattr('equals_string_in') | list
+ or element.all_of | selectattr('equals_number') | list %}
+
+{%- set exactly_one_of_has_extra = element.exactly_one_of | selectattr('pattern') | list
+ or element.exactly_one_of | selectattr('minimum_value') | list
+ or element.exactly_one_of | selectattr('maximum_value') | list
+ or element.exactly_one_of | selectattr('equals_string') | list
+ or element.exactly_one_of | selectattr('equals_string_in') | list
+ or element.exactly_one_of | selectattr('equals_number') | list %}
+
+{%- set none_of_has_extra = element.none_of | selectattr('pattern') | list
+ or element.none_of | selectattr('minimum_value') | list
+ or element.none_of | selectattr('maximum_value') | list
+ or element.none_of | selectattr('equals_string') | list
+ or element.none_of | selectattr('equals_string_in') | list
+ or element.none_of | selectattr('equals_number') | list %}
+
+{%- set has_expressions = (element.any_of and any_of_has_extra) or (element.all_of and all_of_has_extra)
+ or (element.exactly_one_of and exactly_one_of_has_extra) or (element.none_of and none_of_has_extra)
+ or element.equals_expression or element.has_member or element.all_members %}
+
+{%- if has_expressions %}
+
+Expressions & Logic
+
+{%- if element.any_of and any_of_has_extra %}
+#### Any Of
+
+Value must satisfy at least one of:
+
+{%- for expr in element.any_of %}
+- {{ expr_line(expr) }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.all_of and all_of_has_extra %}
+#### All Of
+
+Value must satisfy all of:
+
+{%- for expr in element.all_of %}
+- {{ expr_line(expr) }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.exactly_one_of and exactly_one_of_has_extra %}
+#### Exactly One Of
+
+Value must satisfy exactly one of:
+
+{%- for expr in element.exactly_one_of %}
+- {{ expr_line(expr) }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.none_of and none_of_has_extra %}
+#### None Of
+
+Value must not satisfy any of:
+
+{%- for expr in element.none_of %}
+- {{ expr_line(expr) }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.equals_expression %}
+#### Equals Expression
+
+`{{ element.equals_expression }}`
+{%- endif %}
+
+{%- if element.has_member %}
+#### Has Member
+
+{{ element.has_member }}
+{%- endif %}
+
+{%- if element.all_members %}
+#### All Members
+
+{{ element.all_members }}
+{%- endif %}
+
+
+{% endif %}
+
+{% if schemaview.usage_index().get(element.name) %}
+## Usages
+
+| used by | used in | type | used |
+| --- | --- | --- | --- |
+{% for usage in schemaview.usage_index().get(element.name) -%}
+| {{ gen.link(usage.used_by) }} | {{ gen.link(usage.slot) }} | {{ usage.metaslot }} | {{ gen.link(usage.used) }} |
+{% endfor %}
+{% endif %}
+
+{% include "common_metadata.md.jinja2" %}
+
+## LinkML Source
+
+
+```yaml
+{{ gen.yaml(element) }}
+```
+
+
+{%- if footer -%}
+{{ footer }}
+{%- endif -%}
+
+
diff --git a/docs/templates-linkml/subset.md.jinja2 b/docs/templates-linkml/subset.md.jinja2
new file mode 100644
index 00000000..0a05161d
--- /dev/null
+++ b/docs/templates-linkml/subset.md.jinja2
@@ -0,0 +1,113 @@
+---
+search:
+ boost: {% if element.deprecated %}0.5{% else %}1.0{% endif %}
+---
+
+
+# Subset: {{ gen.name(element) }} {% if element.deprecated %} (DEPRECATED) {% endif %}
+
+{%- if header -%}
+{{ header }}
+{%- endif -%}
+
+{% if element.description %}
+{% set element_description_lines = element.description.split('\n') %}
+{% for element_description_line in element_description_lines %}
+_{{ element_description_line }}_
+{% endfor %}
+{% endif %}
+
+
+
+URI: {{ gen.link(element) }}
+
+{% include "common_metadata.md.jinja2" %}
+
+{% set classes_in_subset = [] %}
+{% set slots_in_subset = [] %}
+{% set enums_in_subset = [] %}
+
+{# Collect classes, slots, and enumerations in subset #}
+{% for c in gen.all_class_objects()|sort(attribute=sort_by) %}
+ {%- if element.name in c.in_subset %}
+ {% set _ = classes_in_subset.append(c) %}
+ {%- endif %}
+{% endfor %}
+
+{% for s in gen.all_slot_objects()|sort(attribute=sort_by) %}
+ {%- if element.name in s.in_subset %}
+ {% set _ = slots_in_subset.append(s) %}
+ {%- endif %}
+{% endfor %}
+
+{% for e in schemaview.all_enums().values() %}
+ {%- if element.name in e.in_subset %}
+ {% set _ = enums_in_subset.append(e) %}
+ {%- endif %}
+{% endfor %}
+
+{% if classes_in_subset %}
+## Classes in subset
+
+| Class | Description |
+| --- | --- |
+{% for c in classes_in_subset -%}
+{%- if element.name in c.in_subset -%}
+| {{ gen.link(c) }} | {{ c.description|enshorten }} |
+{% endif -%}
+{% endfor %}
+
+{% for c in classes_in_subset -%}
+{%- if element.name in c.in_subset -%}
+
+{% set induced_slots = gen.class_induced_slots(c.name)|sort(attribute=sort_by) %}
+
+{%- set filtered_slots = [] -%}
+{%- for s in induced_slots|sort(attribute=sort_by) -%}
+ {%- if element.name in s.in_subset or element.name in schemaview.get_slot(s.name).in_subset -%}
+ {% set _ = filtered_slots.append(s) %}
+ {%- endif -%}
+{%- endfor %}
+
+{%- if filtered_slots|length > 0 -%}
+### Slots from {{ gen.link(c) }} also in _{{ element.name }}_
+
+| Name | Cardinality and Range | Description |
+| --- | --- | --- |
+{% for s in filtered_slots -%}
+| {{ gen.link(s) }} | {{ gen.cardinality(s) }}
{{ gen.link(s.range) }} | {{ s.description|enshorten }} {% if s.identifier %}**identifier**{% endif %} |
+{% endfor %}
+{%- endif %}
+
+{%- endif %}
+{% endfor %}
+
+{%- endif %}
+
+{% if slots_in_subset %}
+## Slots in subset
+
+| Slot | Description |
+| --- | --- |
+{% for s in slots_in_subset|sort(attribute=sort_by) -%}
+{%- if element.name in s.in_subset -%}
+| {{ gen.link(s) }} | {{ s.description|enshorten }} |
+{%- endif %}
+{% endfor %}
+
+{%- endif %}
+
+{% if enums_in_subset %}
+## Enumerations in subset
+
+| Enumeration | Description |
+| --- | --- |
+{% for e in enums_in_subset|sort(attribute='name') -%}
+{% if element.name in e.in_subset -%}
+| {{ gen.link(e) }} | {{ e.description|enshorten }} |
+{%- endif %}
+{% endfor %}
+
+{%- endif %}
+
+
diff --git a/docs/templates-linkml/type.md.jinja2 b/docs/templates-linkml/type.md.jinja2
new file mode 100644
index 00000000..642a6ba8
--- /dev/null
+++ b/docs/templates-linkml/type.md.jinja2
@@ -0,0 +1,170 @@
+---
+search:
+ boost: {% if element.deprecated %}0.5{% else %}1.0{% endif %}
+---
+
+{%- if element.title and element.title != element.name %}
+ {%- set title = element.title ~ ' (' ~ element.name ~ ')' -%}
+{%- else %}
+ {%- set title = gen.name(element) -%}
+{%- endif -%}
+
+# Type: {{ title }} {% if element.deprecated %} (DEPRECATED) {% endif %}
+
+{% if element.description %}
+{% set element_description_lines = element.description.split('\n') %}
+{% for element_description_line in element_description_lines %}
+_{{ element_description_line }}_
+{% endfor %}
+{% endif %}
+
+
+
+URI: {{ gen.uri_link(element) }}
+
+## Type Properties
+
+| Property | Value |
+| --- | --- |
+{%- if element.typeof %}
+| Type Of | {{ gen.link(element.typeof) }} |
+{%- endif %}
+{%- if element.base %}
+| Base | `{{ element.base }}` |
+{%- endif %}
+{%- if element.uri %}
+| Type URI | {{ gen.uri_link(element.uri) }} |
+{%- endif %}
+{%- if element.repr %}
+| Representation | `{{ element.repr }}` |
+{%- endif %}
+{%- if element.union_of %}
+| Union Of | {{ gen.links(element.union_of) | join(', ') }} |
+{%- endif %}
+
+{%- set has_basic_constraints = element.minimum_value is not none or element.maximum_value is not none or element.pattern %}
+
+{%- if has_basic_constraints %}
+## Value Constraints
+
+| Property | Value |
+| --- | --- |
+{%- if element.minimum_value is not none or element.maximum_value is not none %}
+| Numeric Range | {{ gen.number_value_range(element) }} |
+{%- endif %}
+{%- if element.pattern %}
+| Regex Pattern | `{{ element.pattern }}` |
+{%- endif %}
+
+{% endif %}
+{%- set has_advanced_constraints = element.structured_pattern or element.equals_string
+ or element.equals_string_in or element.equals_number or element.unit or element.implicit_prefix %}
+
+{%- if has_advanced_constraints %}
+
+Additional Constraints
+
+{%- if element.structured_pattern %}
+**Structured Pattern:**
+
+- **Syntax:** `{{ element.structured_pattern.syntax }}`
+- **Interpolated:** {{ element.structured_pattern.interpolated }}
+{%- if element.structured_pattern.partial_match %}
+- **Partial Match:** Yes
+{%- endif %}
+{%- endif %}
+
+{%- if element.equals_string %}
+**Must Equal:** `{{ element.equals_string }}`
+{%- endif %}
+
+{%- if element.equals_string_in %}
+**Must Be One Of:** {{ element.equals_string_in | join(', ') }}
+{%- endif %}
+
+{%- if element.equals_number %}
+**Must Equal:** {{ element.equals_number }}
+{%- endif %}
+
+{%- if element.unit %}
+**Unit:**
+
+| Property | Value |
+| --- | --- |
+{%- if element.unit.symbol %}
+| symbol | {{ element.unit.symbol }} |
+{%- endif %}
+{%- if element.unit.abbreviation %}
+| abbreviation | {{ element.unit.abbreviation }} |
+{%- endif %}
+{%- if element.unit.descriptive_name %}
+| descriptive_name | {{ element.unit.descriptive_name }} |
+{%- endif %}
+{%- if element.unit.ucum_code %}
+| ucum_code | {{ element.unit.ucum_code }} |
+{%- endif %}
+{%- if element.unit.derivation %}
+| derivation | {{ element.unit.derivation }} |
+{%- endif %}
+{%- if element.unit.iec61360code %}
+| iec61360code | {{ element.unit.iec61360code }} |
+{%- endif %}
+{%- if element.unit.has_quantity_kind %}
+| has_quantity_kind | {{ gen.uri_link(element.unit.has_quantity_kind) }} |
+{%- endif %}
+{%- if element.unit.exact_mappings %}
+| exact_mappings | {% for m in element.unit.exact_mappings %}{{ gen.uri_link(m) }}{% if not loop.last %}, {% endif %}{% endfor %} |
+{%- endif %}
+{%- endif %}
+
+{%- if element.implicit_prefix %}
+**Implicit Prefix:** {{ element.implicit_prefix }}
+{%- endif %}
+
+
+{% endif %}
+
+{%- set has_expressions = element.any_of or element.all_of or element.exactly_one_of or element.none_of %}
+
+{%- if has_expressions %}
+
+Type Expressions
+
+{%- if element.any_of %}
+**Any Of:** Value must satisfy at least one of these expressions
+
+{%- for expr in element.any_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.all_of %}
+**All Of:** Value must satisfy all of these expressions
+
+{%- for expr in element.all_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.exactly_one_of %}
+**Exactly One Of:** Value must satisfy exactly one of these expressions
+
+{%- for expr in element.exactly_one_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+{%- if element.none_of %}
+**None Of:** Value must not satisfy any of these expressions
+
+{%- for expr in element.none_of %}
+- {{ expr }}
+{%- endfor %}
+{%- endif %}
+
+
+{% endif %}
+
+{% include "common_metadata.md.jinja2" %}
+
+
diff --git a/mkdocs.yml b/mkdocs.yml
index be98403f..18062730 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -12,8 +12,10 @@ theme:
- content.tabs.link
- header.autohide # maximum screen space during scrolling
- navigation.expand # optimize user experience
- - navigation.instant # optimize user experience
- - navigation.instant.progress
+ # The navigation.instant is causing glitchy behavior with the styling
+ # due to a bug in mkdocs.material related to mermaid.
+ #- navigation.instant # optimize user experience
+ #- navigation.instant.progress
- navigation.tracking # update address bar
- search.suggest # suggest good completions
- content.code.copy # enable copy to clipboard