diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000000000000000000000000000000000000..98d4832a4762bd4cbe321f8cbb413a7003886c13
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,2 @@
+src/gql/codegen
+src/assets/theme.css
\ No newline at end of file
diff --git a/README.md b/README.md
index aaa2e843d4c5dbcb69e8d2d55fb7fb473cc78aaf..41f7346a9ea86b53206f8b84365ddb6979fa8f71 100644
--- a/README.md
+++ b/README.md
@@ -86,10 +86,15 @@ import ... from 'componentLib/some3PComponent'
 import ... from '@/components/someLocalComponent'
 import ... from '@/layout/someLayoutComponent'
 import ... from '@/views/someViewComponent'
+/**
+ * Composables imports
+ */
+import ... from '@/composables/useSomeComposable'
+import { ... } from '@vueuse/core'
 /**
  * Other 3rd-party imports
  */
-import { ... } from '@vueuse/core' // For VueUse e.g.
+import { ... } from 'lodash-es'
 /**
  * Stores imports
  */
@@ -97,7 +102,7 @@ import { ... } from '@/stores/someStore'
 /**
  * Types imports
  */
-import { type ... } from 'lib/some3PTypes'
+import { type ... } from 'lib/someTypes'
 import { type ... } from '@/typings/someTypes'
 /**
  * Utils imports
diff --git a/package-lock.json b/package-lock.json
index 88dcb77748fafe58b29b7dfb73a5c04843770dcf..dcd740875af49390748081ee0c4cc92990e25eb4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5046,16 +5046,18 @@
       "dev": true
     },
     "node_modules/@types/lodash": {
-      "version": "4.14.196",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz",
-      "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==",
-      "dev": true
+      "version": "4.17.13",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz",
+      "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==",
+      "dev": true,
+      "license": "MIT"
     },
     "node_modules/@types/lodash-es": {
       "version": "4.17.8",
       "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.8.tgz",
       "integrity": "sha512-euY3XQcZmIzSy7YH5+Unb3b2X12Wtk54YWINBvvGQ5SmMvwb11JQskGsfkH/5HXK77Kr8GF0wkVDIxzAisWtog==",
       "dev": true,
+      "license": "MIT",
       "dependencies": {
         "@types/lodash": "*"
       }
diff --git a/src/assets/icons/alignment.svg b/src/assets/icons/alignment.svg
new file mode 100644
index 0000000000000000000000000000000000000000..653e40e9ed5a0a74d99c446ae1c323676645f848
--- /dev/null
+++ b/src/assets/icons/alignment.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512">
+   <path
+      d="M0 96c0-17.7 14.3-32 32-32h448c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32Zm224 320c0-17.7 14.3-32 32-32h224c17.7 0 32 14.3 32 32s-14.3 32-32 32H256c-17.7 0-32-14.3-32-32zM0 416c0-17.7 14.3-32 32-32h98c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32Zm288-160c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32h224c17.7 0 32 14.3 32 32zm224 0c0 17.7-14.3 32-32 32h-98c-17.7 0-32-14.3-32-32s14.3-32 32-32h98c17.7 0 32 14.3 32 32z"
+      fill="currentColor" />
+</svg>
\ No newline at end of file
diff --git a/src/assets/icons/modification.svg b/src/assets/icons/modification.svg
index cb196bffed9d9cbdc722e0dc2f892a1cd555e7c6..fd6ff998f1c7b35cf55e14ed161762c07907fc01 100644
--- a/src/assets/icons/modification.svg
+++ b/src/assets/icons/modification.svg
@@ -1,5 +1,4 @@
 <svg width="1em" height="1em" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
-
     <path
         style="fill:currentColor"
         d="M56.8 267.5q-17.2-.7-27-8.2-9.9-7.6-13-22.3l-5-24.2 5.9 2H.5l-1.3-6q8.4-6.2 17.5-6.2 6.6 0 10.6 3.7 4.1 3.5 5.4 10.2l2.8 15.4q1.6 9.3 4.4 15 2.8 5.4 7.2 8 4.3 2.5 10.6 3.1h11q4-.3 7-1 3-.8 5.7-2.5 1.4-1.4 3-4.8 1.5-3.4 3-8.2 1.3-4.8 2.3-9.6l3-15.4q1.2-6.7 5.1-10.2 4-3.7 10-3.7 9.2 0 17.5 6.2l-1.2 6h-17.2l5.9-2-5 24q-3.2 14.8-13.2 22.3-10 7.6-27.3 8.4zm-16.3 28.2-.9-4.4q2.8-1.7 6-3.2 3.3-1.7 7.9-3.4l.1 11zm25.7 0 .4-9.9 19.3 2.8-.1 7.1zm-14.5 0v-92h21.2v92zm8.5-82-19.3-2.8.1-7.1h19.6zm10.8 1.1-.2-11h12.7l.9 4.4-6.7 3.5q-3 1.6-6.7 3.1zm60 100.9-5.4-6.5q4.2-3.7 6.7-7.7 2.7-4 2.8-7.7l-7.4-6q.9-5.2 3.8-8.7 3-3.6 7.3-5.9 6.3 2.3 9.3 6.6 3.1 4.2 3.1 9.2 0 5-2.7 10.1-2.6 5.2-7.2 9.5t-10.4 7.1z"
diff --git a/src/assets/style.css b/src/assets/style.css
index b5c61c956711f981a41e95f7fcf0038436cfbb22..45d56fcc15fde275e16056f29d0eda606d18248e 100644
--- a/src/assets/style.css
+++ b/src/assets/style.css
@@ -1,3 +1,9 @@
 @tailwind base;
 @tailwind components;
 @tailwind utilities;
+
+@layer utilities {
+  .small-caps {
+    font-variant: small-caps;
+  }
+}
diff --git a/src/components/AlignmentForm.vue b/src/components/AlignmentForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5aa7d1f32c754d229c22787c476732568aec5dcc
--- /dev/null
+++ b/src/components/AlignmentForm.vue
@@ -0,0 +1,120 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { computed, ref } from 'vue'
+/**
+ * Components imports
+ */
+import AlignmentFormGuide from './AlignmentFormGuide.vue'
+import AlignmentFormTarget from './AlignmentFormTarget.vue'
+import TabView from 'primevue/tabview'
+import TabPanel from 'primevue/tabpanel'
+/**
+ * Types imports
+ */
+import type { AlignmentModesType } from '@/views/AlignmentView.vue'
+import { ALIGNMENT_MODES } from '@/utils/constant'
+/**
+ * Utils imports
+ */
+import { getColorWithOptionalShade } from '@/utils/colors'
+
+/**
+ * Available tabs for type of data to align.
+ */
+enum TabEnum {
+  Guide = 0,
+  Target
+}
+
+/**
+ * Component props
+ */
+const props = defineProps<{
+  /** The current mode. */
+  currentModeModel: AlignmentModesType
+  /** The selected IDs. */
+  selectedIdsModel?: string[]
+}>()
+
+/**
+ * Component events.
+ */
+const emit = defineEmits<{
+  /** Event used to update the `v-model:currentModeModel` value. */
+  'update:currentModeModel': [currentModeModel: AlignmentModesType]
+  /** Event used to update the `v-model:selectedIdsModel` value. */
+  'update:selectedIdsModel': [selectedIdsModel?: string[]]
+}>()
+
+/**
+ * The index of the tab currently selected, reactively updated when changed.
+ */
+const activeTabIndex = computed<TabEnum>({
+  get: () =>
+    ALIGNMENT_MODES.findIndex((mode) => mode === props.currentModeModel),
+  set: (newTabIndex) =>
+    emit('update:currentModeModel', ALIGNMENT_MODES[newTabIndex])
+})
+
+/**
+ * The IDs of the sequences selected for alignment.
+ */
+const selectedIds = ref<{
+  /** The IDs of the guides selected for alignment. */
+  guide: string[]
+  /** The IDs of the targets selected for alignment. */
+  target: string[]
+}>({
+  guide: [],
+  target: []
+})
+</script>
+
+<template>
+  <TabView
+    v-model:active-index="activeTabIndex"
+    :pt="{
+      nav: {
+        style: {
+          justifyContent: 'center',
+          marginBottom: '2rem',
+          fontSize: '1.25em',
+          background: `linear-gradient(white 0 0) padding-box,
+                linear-gradient(90deg,
+                  ${getColorWithOptionalShade('slate', '300')}00 10%,
+                  ${getColorWithOptionalShade('slate', '300')}   15%,
+                  ${getColorWithOptionalShade('slate', '300')}   85%,
+                  ${getColorWithOptionalShade('slate', '300')}00 90%)
+                border-box`,
+          borderStyle: 'dashed',
+          borderColor: 'white'
+        }
+      }
+    }"
+    @tab-change="$emit('update:selectedIdsModel', [])"
+  >
+    <TabPanel header="Guide">
+      <AlignmentFormGuide
+        v-model:selected-guide-ids-model="selectedIds.guide"
+        class="mx-auto rounded-xl border border-slate-300 bg-slate-50 p-8"
+        @update:selected-guide-ids-model="
+          (newSelectedGuideIds) =>
+            $emit('update:selectedIdsModel', newSelectedGuideIds)
+        "
+      />
+    </TabPanel>
+
+    <TabPanel header="Target">
+      <AlignmentFormTarget
+        v-model:selected-target-ids-model="selectedIds.target"
+        class="mx-auto rounded-xl border border-slate-300 bg-slate-50 p-8"
+        @update:selected-target-ids-model="
+          (newSelectedTargetIds) =>
+            $emit('update:selectedIdsModel', newSelectedTargetIds)
+        "
+      />
+    </TabPanel>
+  </TabView>
+</template>
diff --git a/src/components/AlignmentFormGuide.vue b/src/components/AlignmentFormGuide.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9e01148e1332057e879bf830b72b10ed068b40da
--- /dev/null
+++ b/src/components/AlignmentFormGuide.vue
@@ -0,0 +1,364 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { computed, ref, toRef } from 'vue'
+/**
+ * Components imports
+ */
+import BaseRenderedMarkdown from '@/components/BaseRenderedMarkdown.vue'
+import SelectButton from 'primevue/selectbutton'
+import Chip from 'primevue/chip'
+import MultiSelect from 'primevue/multiselect'
+import Dropdown from 'primevue/dropdown'
+/**
+ * Composables imports
+ */
+import { useQuery } from '@urql/vue'
+/**
+ * Other 3rd-party imports
+ */
+import {
+  uniqWith as _uniqWith,
+  isEqual as _isEqual,
+  groupBy as _groupBy,
+  mapValues as _mapValues
+} from 'lodash-es'
+/**
+ * Types imports
+ */
+import type { GuideClass } from '@/gql/codegen/graphql'
+/**
+ * Utils imports
+ */
+import { guideAlignmentQuery } from '@/gql/queries'
+
+interface GuideAlignmentSelectionModel {
+  /** Currently selected guide subclasses. */
+  guideSubclasses: GuideClass[]
+  /** Currently selected guide name. */
+  guideName: string | undefined
+  /** Currently selected organism IDs.*/
+  organismIds: number[]
+  /** Currently selected guide IDs for alignment. */
+  guideIds: string[]
+}
+
+/**
+ * Component props
+ */
+defineProps<{
+  /** The currently selected guide IDs for alignment. */
+  selectedGuideIdsModel?: string[]
+}>()
+
+/**
+ * Component events.
+ */
+const emit = defineEmits<{
+  /** Event used to update the `v-model:selectedGuideIdsModel` value. */
+  'update:selectedGuideIdsModel': [selectedGuideIdsModel?: string[]]
+}>()
+
+/**
+ * Current selection of parameters/filters for the guides to pick.
+ */
+const selection = ref<GuideAlignmentSelectionModel>({
+  guideSubclasses: [],
+  guideName: undefined,
+  organismIds: [],
+  guideIds: []
+})
+
+/**
+ * Reactive urql GraphQL query object, updated with query state & response.
+ */
+const gqlQuery = useQuery({
+  query: guideAlignmentQuery,
+  variables: toRef(() => ({
+    guideSubclasses: selection.value.guideSubclasses.length
+      ? selection.value.guideSubclasses
+      : undefined,
+    guideName: selection.value.guideName || '',
+    organismIds: selection.value.organismIds.length
+      ? selection.value.organismIds
+      : undefined
+  }))
+})
+
+/**
+ * Available options for guide subclass selection, independently of other fields'
+ * selection.
+ */
+const guideSubclassOptions = computed(() =>
+  _uniqWith(
+    gqlQuery.data.value?.guideBase,
+    (guideA, guideB) => guideA.subclass === guideB.subclass
+  ).map((guide) => ({
+    label: guide.subclass_label,
+    value: guide.subclass
+  }))
+)
+
+/**
+ * Available options for guide name selection, independently of other fields'
+ * selection.
+ */
+const guideNameOptionsBase = computed(() =>
+  _uniqWith(
+    gqlQuery.data.value?.guideBase,
+    (guideA, guideB) => guideA.name === guideB.name
+  ).map((guide) => ({
+    label: guide.name,
+    value: guide.name
+  }))
+)
+
+/**
+ * Available guide names, filtered based on other fields' selection (only guide
+ * names which exists with selected options are present).
+ */
+const guideNamesFiltered = computed(() =>
+  _uniqWith(
+    gqlQuery.data.value?.guideNamesFilteredBySubclass,
+    (guideA, guideB) => guideA.name === guideB.name
+  ).map((guide) => guide.name)
+)
+
+/**
+ * Available options for guide name selection, with a `isDisabled` field on
+ * absence in `guideNamesFiltered`.
+ */
+const guideNameOptionsWithDisabling = computed(() =>
+  guideNameOptionsBase.value.map((guideNameOption) => ({
+    ...guideNameOption,
+    isDisabled: !guideNamesFiltered.value.some(
+      (guideNameFiltered) => guideNameFiltered === guideNameOption.value
+    )
+  }))
+)
+
+/**
+ * Available options for organism ID selection, independently of other fields'
+ * selection.
+ */
+const organismIdOptionsBase = computed(() =>
+  _uniqWith(gqlQuery.data.value?.organismsBase, _isEqual).map((organism) => ({
+    label: organism.label,
+    value: organism.id
+  }))
+)
+
+/**
+ * For each guide name, an array of the IDs of the organisms which have at
+ * least a guide of this name registered.
+ */
+const organismIdsByGuideNameBase = computed(() =>
+  _mapValues(
+    _groupBy(_uniqWith(gqlQuery.data.value?.guideBase, _isEqual), 'name'),
+    (guides) => guides.map((guide) => guide.genome?.organism?.id)
+  )
+)
+
+/**
+ * Available organism IDs, filtered based on other fields' selection (only
+ * organism IDs which exists with selected options are present).
+ */
+const organismIdsFiltered = computed(
+  () =>
+    (selection.value.guideName &&
+      organismIdsByGuideNameBase.value[selection.value.guideName]) ||
+    []
+)
+
+/**
+ * Available options for organism ID selection, with a `isDisabled` field on
+ * absence in `organismIdsFiltered`.
+ */
+const organismIdOptionsWithDisabling = computed(() =>
+  organismIdOptionsBase.value.map((organismIdOption) => ({
+    ...organismIdOption,
+    isDisabled: !organismIdsFiltered.value.some(
+      (organismIdFiltered) => organismIdFiltered === organismIdOption.value
+    )
+  }))
+)
+
+/**
+ * Available options for guide ID selection for alignment given the other
+ * fields selection.
+ */
+const guideIdOptions = computed(() =>
+  gqlQuery.data.value?.selectableGuides.map((guide) => ({
+    label: guide.id,
+    optionLabel: `\`${guide.id}\` • ${guide.genome?.organism?.shortlabel}`,
+    value: guide.id
+  }))
+)
+
+/**
+ * Clear the selected guide IDs.
+ */
+const clearGuideIds = () => {
+  emit('update:selectedGuideIdsModel', (selection.value.guideIds = []))
+}
+
+/**
+ * Remove an organism ID from the selected ones & clear the selected guide IDs.
+ */
+const removeOrganismAndClearGuideIds = (organismId: number) => {
+  const organismIdIndex = selection.value.organismIds.findIndex(
+    (currOrganismId) => currOrganismId === organismId
+  )
+  organismIdIndex !== -1 &&
+    selection.value.organismIds.splice(organismIdIndex, 1)
+  clearGuideIds()
+}
+
+/**
+ * Clear the selected organisms & guide IDs.
+ */
+const clearOrganismsAndGuideIds = () => {
+  selection.value.organismIds = selection.value.organismIds.filter(
+    (organismId) =>
+      selection.value.guideName &&
+      organismIdsByGuideNameBase.value[selection.value.guideName]?.includes(
+        organismId
+      )
+  )
+  clearGuideIds()
+}
+
+/**
+ * Clear the selection except the selected guide subclass.
+ */
+const clearSelectionExceptSubclass = () => {
+  selection.value.guideName = undefined
+  clearOrganismsAndGuideIds()
+}
+</script>
+
+<template>
+  <div class="flex max-w-max flex-wrap gap-8">
+    <div class="flex flex-col gap-2">
+      <h3 class="text-lg font-bold text-slate-700">Guide subclasses</h3>
+      <SelectButton
+        v-model="selection.guideSubclasses"
+        :options="guideSubclassOptions"
+        option-label="label"
+        option-value="value"
+        option-disabled="isDisabled"
+        multiple
+        @change="clearSelectionExceptSubclass"
+      >
+        <template #option="{ option }">
+          <BaseRenderedMarkdown
+            :stringified-markdown="option.label"
+            class="font-medium"
+          />
+        </template>
+      </SelectButton>
+    </div>
+
+    <div class="flex max-w-min flex-col gap-2">
+      <h3 class="text-lg font-bold text-slate-700">Guides</h3>
+      <Dropdown
+        v-model="selection.guideName"
+        :options="guideNameOptionsWithDisabling"
+        option-label="label"
+        option-value="value"
+        option-disabled="isDisabled"
+        placeholder="Select a guide..."
+        filter
+        @change="clearOrganismsAndGuideIds"
+      />
+    </div>
+
+    <div
+      v-tooltip.bottom="
+        !selection.guideName && {
+          value: 'First select a guide to list its organisms.',
+          autoHide: false,
+          pt: { text: { style: { textAlign: 'center' } } }
+        }
+      "
+      class="flex max-w-min flex-col gap-2"
+    >
+      <h3 class="text-lg font-bold text-slate-700">Organisms</h3>
+      <MultiSelect
+        v-model="selection.organismIds"
+        :options="organismIdOptionsWithDisabling"
+        option-label="label"
+        option-value="value"
+        option-disabled="isDisabled"
+        multiple
+        placeholder="Select organisms..."
+        :max-selected-labels="3"
+        display="chip"
+        filter
+        :disabled="!selection.guideName"
+        @change="clearGuideIds"
+      >
+        <template #value>
+          <Chip
+            v-for="organismId in selection.organismIds.slice(0, 3)"
+            :key="organismId"
+            class="mr-1"
+            removable
+            @remove.stop="removeOrganismAndClearGuideIds(organismId)"
+          >
+            <BaseRenderedMarkdown
+              :stringified-markdown="
+                organismIdOptionsBase.find(
+                  (organismIdOption) => organismIdOption.value === organismId
+                )?.label || ''
+              "
+              class="my-1.5"
+            />
+          </Chip>
+          <template v-if="selection.organismIds.length > 3">
+            +{{ selection.organismIds.length - 3 }} others...
+          </template>
+        </template>
+        <template #option="{ option }">
+          <BaseRenderedMarkdown :stringified-markdown="option.label" />
+        </template>
+      </MultiSelect>
+    </div>
+
+    <div
+      v-tooltip.bottom="
+        !selection.guideName && {
+          value: 'First select a guide to list its sequences.',
+          autoHide: false,
+          pt: { text: { style: { textAlign: 'center' } } }
+        }
+      "
+      class="flex max-w-min flex-col gap-2"
+    >
+      <h3 class="text-lg font-bold text-slate-700">Sequences</h3>
+      <MultiSelect
+        v-model="selection.guideIds"
+        :options="guideIdOptions"
+        option-label="label"
+        option-value="value"
+        multiple
+        placeholder="Select sequences..."
+        :max-selected-labels="3"
+        filter
+        :disabled="!selection.guideName"
+        empty-message="First select a guide to list its sequences"
+        @update:model-value="(selectedGuideIdsModel: string[]) => $emit('update:selectedGuideIdsModel', selectedGuideIdsModel)"
+      >
+        <template #option="{ option }">
+          <BaseRenderedMarkdown :stringified-markdown="option.optionLabel" />
+        </template>
+        <template #value="{ value }">
+          <span v-if="value.length" class="font-mono">
+            {{ value.join(', ') }}
+          </span>
+        </template>
+      </MultiSelect>
+    </div>
+  </div>
+</template>
diff --git a/src/components/AlignmentFormTarget.vue b/src/components/AlignmentFormTarget.vue
new file mode 100644
index 0000000000000000000000000000000000000000..8f5b96271cfb6262aa2df21b842838114fd96f3d
--- /dev/null
+++ b/src/components/AlignmentFormTarget.vue
@@ -0,0 +1,301 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { computed, ref, toRef } from 'vue'
+/**
+ * Components imports
+ */
+import BaseRenderedMarkdown from '@/components/BaseRenderedMarkdown.vue'
+import Chip from 'primevue/chip'
+import MultiSelect from 'primevue/multiselect'
+import Dropdown from 'primevue/dropdown'
+/**
+ * Composables imports
+ */
+import { useQuery } from '@urql/vue'
+/**
+ * Other 3rd-party imports
+ */
+import {
+  uniqWith as _uniqWith,
+  isEqual as _isEqual,
+  groupBy as _groupBy,
+  mapValues as _mapValues
+} from 'lodash-es'
+/**
+ * Utils imports
+ */
+import { targetAlignmentQuery } from '@/gql/queries'
+
+interface TargetAlignmentSelectionModel {
+  /** Currently selected target name. */
+  targetName: string | undefined
+  /** Currently selected organism IDs.*/
+  organismIds: number[]
+  /** Currently selected target IDs for alignment. */
+  targetIds: string[]
+}
+
+/**
+ * Component props
+ */
+defineProps<{
+  /** The currently selected target IDs for alignment. */
+  selectedTargetIdsModel?: string[]
+}>()
+
+/**
+ * Component events.
+ */
+const emit = defineEmits<{
+  /** Event used to update the `v-model:selectedTargetIdsModel` value. */
+  'update:selectedTargetIdsModel': [selectedTargetIdsModel?: string[]]
+}>()
+
+/**
+ * Current selection of parameters/filters for the target sequences to pick.
+ */
+const selection = ref<TargetAlignmentSelectionModel>({
+  targetName: undefined,
+  organismIds: [],
+  targetIds: []
+})
+
+/**
+ * Reactive urql GraphQL query object, updated with query state & response.
+ */
+const gqlQuery = useQuery({
+  query: targetAlignmentQuery,
+  variables: toRef(() => ({
+    targetName: selection.value.targetName || '',
+    organismIds: selection.value.organismIds.length
+      ? selection.value.organismIds
+      : undefined
+  }))
+})
+
+/**
+ * Available options for target name selection, independently of other fields'
+ * selection.
+ */
+const targetNameOptionsGroups = computed(() =>
+  Object.entries(
+    _groupBy(
+      _uniqWith(
+        gqlQuery.data.value?.targetBase,
+        (targetA, targetB) => targetA.name === targetB.name
+      ).map((target) => ({
+        label: target.name,
+        value: target.name,
+        groupLabel: target.unit || 'Other'
+      })),
+      'groupLabel'
+    )
+  ).map(([targetUnit, targets]) => ({ label: targetUnit, children: targets }))
+)
+
+/**
+ * Available options for organism ID selection, independently of other fields'
+ * selection.
+ */
+const organismIdOptionsBase = computed(() =>
+  _uniqWith(gqlQuery.data.value?.organismsBase, _isEqual).map((organism) => ({
+    label: organism.label,
+    value: organism.id
+  }))
+)
+
+/**
+ * For each target name, an array of the IDs of the organisms which have at
+ * least a target of this name registered.
+ */
+const organismIdsByTargetNameBase = computed(() =>
+  _mapValues(
+    _groupBy(_uniqWith(gqlQuery.data.value?.targetBase, _isEqual), 'name'),
+    (targets) => targets.map((target) => target.genome?.organism?.id)
+  )
+)
+
+/**
+ * Available organism IDs, filtered based on other fields' selection (only
+ * organism IDs which exists with selected options are present).
+ */
+const organismIdsFiltered = computed(
+  () =>
+    (selection.value.targetName &&
+      organismIdsByTargetNameBase.value[selection.value.targetName]) ||
+    []
+)
+
+/**
+ * Available options for organism ID selection, with a `isDisabled` field on
+ * absence in `organismIdsFiltered`.
+ */
+const organismIdOptionsWithDisabling = computed(() =>
+  organismIdOptionsBase.value.map((organismIdOption) => ({
+    ...organismIdOption,
+    isDisabled: !organismIdsFiltered.value.some(
+      (organismIdFiltered) => organismIdFiltered === organismIdOption.value
+    )
+  }))
+)
+
+/**
+ * Available options for target ID selection for alignment given the other
+ * fields selection.
+ */
+const targetIdOptions = computed(() =>
+  gqlQuery.data.value?.selectableTargets.map((target) => ({
+    label: target.id,
+    optionLabel: `\`${target.id}\` • ${target.genome?.organism?.shortlabel}`,
+    value: target.id
+  }))
+)
+
+/**
+ * Clear the selected target IDs.
+ */
+const clearTargetIds = () => {
+  emit('update:selectedTargetIdsModel', (selection.value.targetIds = []))
+}
+
+/**
+ * Remove an organism ID from the selected ones & clear the selected target IDs.
+ */
+const removeOrganismAndClearTargetIds = (organismId: number) => {
+  const organismIdIndex = selection.value.organismIds.findIndex(
+    (currOrganismId) => currOrganismId === organismId
+  )
+  organismIdIndex !== -1 &&
+    selection.value.organismIds.splice(organismIdIndex, 1)
+  clearTargetIds()
+}
+
+/**
+ * Clear the selected organisms & target IDs.
+ */
+const clearOrganismsAndTargetIds = () => {
+  selection.value.organismIds = selection.value.organismIds.filter(
+    (organismId) =>
+      selection.value.targetName &&
+      organismIdsByTargetNameBase.value[selection.value.targetName]?.includes(
+        organismId
+      )
+  )
+  clearTargetIds()
+}
+</script>
+
+<template>
+  <div class="flex max-w-max flex-wrap gap-8">
+    <div class="flex max-w-min flex-col gap-2">
+      <h3 class="text-lg font-bold text-slate-700">Targets</h3>
+      <Dropdown
+        v-model="selection.targetName"
+        :options="targetNameOptionsGroups"
+        option-label="label"
+        option-value="value"
+        option-group-label="label"
+        option-group-children="children"
+        placeholder="Select a target..."
+        filter
+        :pt="{
+          item: {
+            style: {
+              marginLeft: '1rem'
+            }
+          }
+        }"
+        @change="clearOrganismsAndTargetIds"
+      />
+    </div>
+
+    <div
+      v-tooltip.bottom="
+        !selection.targetName && {
+          value: 'First select a target to list its organisms.',
+          autoHide: false,
+          pt: { text: { style: { textAlign: 'center' } } }
+        }
+      "
+      class="flex max-w-min flex-col gap-2"
+    >
+      <h3 class="text-lg font-bold text-slate-700">Organisms</h3>
+      <MultiSelect
+        v-model="selection.organismIds"
+        :options="organismIdOptionsWithDisabling"
+        option-label="label"
+        option-value="value"
+        option-disabled="isDisabled"
+        multiple
+        placeholder="Select organisms..."
+        :max-selected-labels="3"
+        display="chip"
+        filter
+        :disabled="!selection.targetName"
+        @change="clearTargetIds"
+      >
+        <template #value>
+          <Chip
+            v-for="organismId in selection.organismIds.slice(0, 3)"
+            :key="organismId"
+            class="mr-1"
+            removable
+            @remove.stop="removeOrganismAndClearTargetIds(organismId)"
+          >
+            <BaseRenderedMarkdown
+              :stringified-markdown="
+                organismIdOptionsBase.find(
+                  (organismIdOption) => organismIdOption.value === organismId
+                )?.label || ''
+              "
+              class="my-1.5"
+            />
+          </Chip>
+          <template v-if="selection.organismIds.length > 3">
+            +{{ selection.organismIds.length - 3 }} others...
+          </template>
+        </template>
+        <template #option="{ option }">
+          <BaseRenderedMarkdown :stringified-markdown="option.label" />
+        </template>
+      </MultiSelect>
+    </div>
+
+    <div
+      v-tooltip.bottom="
+        !selection.targetName && {
+          value: 'First select a target to list its sequences.',
+          autoHide: false,
+          pt: { text: { style: { textAlign: 'center' } } }
+        }
+      "
+      class="flex max-w-min flex-col gap-2"
+    >
+      <h3 class="text-lg font-bold text-slate-700">Sequences</h3>
+      <MultiSelect
+        v-model="selection.targetIds"
+        :options="targetIdOptions"
+        option-label="label"
+        option-value="value"
+        multiple
+        placeholder="Select sequences..."
+        :max-selected-labels="3"
+        filter
+        :disabled="!selection.targetName"
+        empty-message="First select a target to list its sequences"
+        @update:model-value="(selectedTargetIds: string[]) => $emit('update:selectedTargetIdsModel', selectedTargetIds)"
+      >
+        <template #option="{ option }">
+          <BaseRenderedMarkdown :stringified-markdown="option.optionLabel" />
+        </template>
+        <template #value="{ value }">
+          <span v-if="value.length" class="font-mono">
+            {{ value.join(', ') }}
+          </span>
+        </template>
+      </MultiSelect>
+    </div>
+  </div>
+</template>
diff --git a/src/components/BaseLegendButtonOverlay.vue b/src/components/BaseLegendButtonOverlay.vue
index 68f0f79a1bf4dd8120e1d958e81e2e92e7a8bb27..058299341d2aa98d4408c29cfebbd0bcbb2e6ead 100644
--- a/src/components/BaseLegendButtonOverlay.vue
+++ b/src/components/BaseLegendButtonOverlay.vue
@@ -4,7 +4,7 @@
  */
 import { ref } from 'vue'
 /**
- * Component imports
+ * Components imports
  */
 import Button from 'primevue/button'
 import OverlayPanel from 'primevue/overlaypanel'
diff --git a/src/components/BaseLockableTooltip.vue b/src/components/BaseLockableTooltip.vue
index 52fb6f14caa4c73905e6fe597988f8af31dfc19a..d7d5c0f88dba2883f89e81efcdd53b35be37be01 100644
--- a/src/components/BaseLockableTooltip.vue
+++ b/src/components/BaseLockableTooltip.vue
@@ -8,7 +8,7 @@ import { computed, ref } from 'vue'
  */
 import BaseTooltip from '@/components/BaseTooltip.vue'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useMouse, onClickOutside } from '@vueuse/core'
 
diff --git a/src/components/ChromosomeMagnify.vue b/src/components/ChromosomeMagnify.vue
index a9538657e3e4c51d3cc51b007343c09362b96ea8..300add17373f65a9f317061af39b9ef823b49248 100644
--- a/src/components/ChromosomeMagnify.vue
+++ b/src/components/ChromosomeMagnify.vue
@@ -8,9 +8,12 @@ import { computed, onMounted, ref } from 'vue'
  */
 import BaseLockableTooltip from '@/components/BaseLockableTooltip.vue'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useMouseInElement } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
 import { G, Rect, SVG, type Svg } from '@svgdotjs/svg.js'
 /**
  * Types imports
diff --git a/src/components/HelpDialog.vue b/src/components/HelpDialog.vue
index 225a44c8416be166b50d6dc634cf6e0b090eb63d..1254b4f7bee309022f1392500f5f77d166578343 100644
--- a/src/components/HelpDialog.vue
+++ b/src/components/HelpDialog.vue
@@ -4,7 +4,7 @@
  */
 import { ref, watchEffect } from 'vue'
 /**
- * Component imports
+ * Components imports
  */
 import Dialog from 'primevue/dialog'
 import Carousel from 'primevue/carousel'
diff --git a/src/components/InteractionCard.vue b/src/components/InteractionCard.vue
index 17dd546847cd57db689774a1d3493862c769437c..757548bb4608cf8731d7cb2df0255ccc018d3f0f 100644
--- a/src/components/InteractionCard.vue
+++ b/src/components/InteractionCard.vue
@@ -142,9 +142,9 @@ const HACAFormattedInteraction = computed<InteractionHACAModel | undefined>(
   () => {
     if (props.interaction?.modification.type === ModifType.Psi) {
       const duplexes = {
-        before: props.interaction.duplexes.find((duplex) => duplex.index === 1),
-        middle: props.interaction.duplexes.find((duplex) => duplex.index === 2),
-        after: props.interaction.duplexes.find((duplex) => duplex.index === 3)
+        before: props.interaction.duplexes.find((duplex) => duplex.index === 0),
+        middle: props.interaction.duplexes.find((duplex) => duplex.index === 1),
+        after: props.interaction.duplexes.find((duplex) => duplex.index === 2)
       }
 
       if (
diff --git a/src/components/InteractionCardCD.vue b/src/components/InteractionCardCD.vue
index 01f46763033bfa378ed1f787f227ebedaa6478fc..3d445222a561829828fbe9e2d591233ba25a62ad 100644
--- a/src/components/InteractionCardCD.vue
+++ b/src/components/InteractionCardCD.vue
@@ -223,7 +223,9 @@ const bondsText = computed(() =>
       const basePair =
         nucleotide + paddedFragments.value.target[nucleotidePositionInDuplex] ||
         ''
-      return /GC|CG|AU|UA/.test(basePair)
+      return nucleotidePositionInDuplex === modificationPositionInDuplex.value
+        ? ' '
+        : /GC|CG|AU|UA/.test(basePair)
         ? '|'
         : /GU|UG/.test(basePair) &&
           nucleotidePositionInDuplex > firstBondPositionInDuplex.value &&
diff --git a/src/components/InteractionCardHACA.vue b/src/components/InteractionCardHACA.vue
index 9d5046ba9309b3fe8221ec21955eb04c73b05612..35b93e0fd30d5e32577ab53d3929812c5f1fe4ca 100644
--- a/src/components/InteractionCardHACA.vue
+++ b/src/components/InteractionCardHACA.vue
@@ -9,7 +9,8 @@ import { ref, computed } from 'vue'
 import {
   isEqual as _isEqual,
   reverse as _reverse,
-  findLastIndex as _findLastIndex
+  findLastIndex as _findLastIndex,
+  mapValues as _mapValues
 } from 'lodash-es'
 /**
  * Types imports
@@ -349,45 +350,42 @@ const lastBondIndex = computed(() =>
  * Texts representing the bonds w/ their nature
  */
 const bondsTexts = computed(() =>
-  Object.entries({
-    before: [
-      splitPaddedFragments.value.guide.first.before,
-      splitPaddedFragments.value.target.before
-    ],
-    middle: [
-      splitPaddedFragments.value.guide.first.middle,
-      _reverse(splitPaddedFragments.value.guide.second.middle.split('')).join(
-        ''
-      )
-    ],
-    after: [
-      splitPaddedFragments.value.guide.second.after,
-      splitPaddedFragments.value.target.after
-    ]
-  }).reduce<{ [duplexId: string]: string }>(
-    (bondsTexts, [duplexId, fragmentPair]) => ({
-      ...bondsTexts,
-      [duplexId]:
-        fragmentPair[0]
-          ?.split('')
-          .map((nucleotide, inDuplexNucleotideIndex) => {
-            const basePair =
-              nucleotide + fragmentPair[1]?.[inDuplexNucleotideIndex] || ''
-            return /GC|CG|AU|UA/.test(basePair)
-              ? '|'
-              : /GU|UG/.test(basePair) &&
-                inDuplexNucleotideIndex > firstBondIndex.value &&
-                inDuplexNucleotideIndex < lastBondIndex.value
-              ? '∙'
-              : /GA|AG/.test(basePair) &&
-                inDuplexNucleotideIndex > firstBondIndex.value &&
-                inDuplexNucleotideIndex < lastBondIndex.value
-              ? 'â—‹'
-              : ' '
-          })
-          .join('') || ''
-    }),
-    {}
+  _mapValues(
+    {
+      before: [
+        splitPaddedFragments.value.guide.first.before,
+        splitPaddedFragments.value.target.before
+      ],
+      middle: [
+        splitPaddedFragments.value.guide.first.middle,
+        _reverse(splitPaddedFragments.value.guide.second.middle.split('')).join(
+          ''
+        )
+      ],
+      after: [
+        splitPaddedFragments.value.guide.second.after,
+        splitPaddedFragments.value.target.after
+      ]
+    },
+    (fragmentPair) =>
+      fragmentPair[0]
+        ?.split('')
+        .map((nucleotide, inDuplexNucleotideIndex) => {
+          const basePair =
+            nucleotide + fragmentPair[1]?.[inDuplexNucleotideIndex] || ''
+          return /GC|CG|AU|UA/.test(basePair)
+            ? '|'
+            : /GU|UG/.test(basePair) &&
+              inDuplexNucleotideIndex > firstBondIndex.value &&
+              inDuplexNucleotideIndex < lastBondIndex.value
+            ? '∙'
+            : /GA|AG/.test(basePair) &&
+              inDuplexNucleotideIndex > firstBondIndex.value &&
+              inDuplexNucleotideIndex < lastBondIndex.value
+            ? 'â—‹'
+            : ' '
+        })
+        .join('') || ''
   )
 )
 
diff --git a/src/components/KaryotypeBoard.vue b/src/components/KaryotypeBoard.vue
index 3eecb1199eb97ba399de2406a2c23ef82cac0ded..e7aa613efa7ce8a31c48147adc3e3517ea2d2019 100644
--- a/src/components/KaryotypeBoard.vue
+++ b/src/components/KaryotypeBoard.vue
@@ -9,12 +9,15 @@ import { computed, onMounted, ref } from 'vue'
 import Button from 'primevue/button'
 import IconTablerCircleArrowLeft from '~icons/tabler/circle-arrow-left'
 import IconTablerCircleArrowLeftFilled from '~icons/tabler/circle-arrow-left-filled'
+/**
+ * Composables imports
+ */
+import { useElementBounding, useWindowScroll } from '@vueuse/core'
 /**
  * Other 3rd-party imports
  */
 import { SVG, Svg } from '@svgdotjs/svg.js'
 import { find as _find } from 'lodash-es'
-import { useElementBounding, useWindowScroll } from '@vueuse/core'
 /**
  * Types imports
  */
@@ -117,7 +120,10 @@ const expandedChromosomeLength = computed(() =>
  */
 const longestChromosome = computed(() =>
   props.chromosomes.reduce(
-    (longestChromosome, currChromosome) => (longestChromosome && currChromosome.length > longestChromosome.length ? currChromosome : longestChromosome),
+    (longestChromosome, currChromosome) =>
+      longestChromosome && currChromosome.length > longestChromosome.length
+        ? currChromosome
+        : longestChromosome,
     props.chromosomes[0]
   )
 )
@@ -129,7 +135,7 @@ const objectsByChromosome = computed(() =>
   props.chromosomes.reduce<{ [k: string]: GenomeObjectModel[] }>(
     (objectsByChromosome, currChromosome) => ({
       ...objectsByChromosome,
-      [currChromosome.id] : (props.objects || []).filter(
+      [currChromosome.id]: (props.objects || []).filter(
         (object) => object.chromosomeId === currChromosome.id
       )
     }),
diff --git a/src/components/SecondaryStructure.vue b/src/components/SecondaryStructure.vue
index d6f1490415c5d671a391e34c6778def16e827055..e3076650e1a336ea033d7a8e8d4581df16813064 100644
--- a/src/components/SecondaryStructure.vue
+++ b/src/components/SecondaryStructure.vue
@@ -19,10 +19,13 @@ import IconFa6SolidCropSimple from '~icons/fa6-solid/crop-simple'
 import IconFa6SolidExpand from '~icons/fa6-solid/expand'
 import IconFa6SolidDownload from '~icons/fa6-solid/download'
 /**
- * Other3rd-party imports
+ * Composables imports
  */
-import G6 from '@antv/g6'
 import { useElementSize, useResizeObserver } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
+import G6 from '@antv/g6'
 import { find as _find } from 'lodash-es'
 import mime from 'mime'
 import FileSaver from 'file-saver'
diff --git a/src/components/SelectionForm.vue b/src/components/SelectionForm.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4738b92058be52565b532f8ec6716d5994a7f871
--- /dev/null
+++ b/src/components/SelectionForm.vue
@@ -0,0 +1,166 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { computed, ref, watch } from 'vue'
+/**
+ * Components imports
+ */
+import SelectionFormGuide from './SelectionFormGuide.vue'
+import SelectionFormTarget from './SelectionFormTarget.vue'
+import SelectionFormModification from './SelectionFormModification.vue'
+import TabView from 'primevue/tabview'
+import TabPanel from 'primevue/tabpanel'
+/**
+ * Types imports
+ */
+import type { SelectionModesType } from '@/views/SelectionView.vue'
+import type { GuideSelectionModel } from './SelectionFormGuide.vue'
+import type { TargetSelectionModel } from './SelectionFormTarget.vue'
+import type { ModificationSelectionModel } from './SelectionFormModification.vue'
+import { SELECTION_MODES } from '@/utils/constant'
+/**
+ * Utils imports
+ */
+import { getColorWithOptionalShade } from '@/utils/colors'
+
+/**
+ * A selection for the different modes.
+ */
+export interface SelectionModel {
+  /** The selection of the modification. */
+  modification?: ModificationSelectionModel
+  /** The selection of the guide. */
+  guide?: GuideSelectionModel
+  /** The selection of the target. */
+  target?: TargetSelectionModel
+}
+
+/**
+ * Available tabs for type of data to select.
+ */
+enum TabEnum {
+  Modification = 0,
+  Guide,
+  Target
+}
+
+/**
+ * Component props
+ */
+const props = defineProps<{
+  /** The current mode. */
+  currentModeModel: SelectionModesType
+  /** The current selection in the different modes (v-model value). */
+  selectionModel: SelectionModel
+  /** The ID of the target which matches the selection if it is unique (v-model
+   * value). */
+  onlyTargetIdByModeModel: { modification?: string; target?: string }
+}>()
+
+/**
+ * Component events.
+ */
+const emit = defineEmits<{
+  /** Event used to update the `v-model:currentModeModel` value. */
+  'update:currentModeModel': [currentModeModel: SelectionModesType]
+  /** Event used to update the `v-model:selectionModel` value. */
+  'update:selectionModel': [selectionModel: SelectionModel]
+  /** Event used to update the `v-model:onlyTargetIdByModeModel` value. */
+  'update:onlyTargetIdByModeModel': [
+    onlyTargetIdByModeModel: { modification?: string; target?: string }
+  ]
+}>()
+
+/**
+ * The index of the tab currently selected, reactively updated when changed.
+ */
+const activeTabIndex = computed<TabEnum>({
+  get: () =>
+    SELECTION_MODES.findIndex((mode) => mode === props.currentModeModel),
+  set: (newTabIndex) =>
+    emit('update:currentModeModel', SELECTION_MODES[newTabIndex])
+})
+
+/**
+ * The current selection in the different modes (local value).
+ */
+const selection = ref<SelectionModel>({
+  modification: undefined,
+  guide: undefined,
+  target: undefined
+})
+
+/**
+ * The ID of the target which matches the selection if it is unique (i.e. a
+ * single target name & a single species is selected), `undefined` otherwise.
+ * One target ID is used for each mode able to provide one (local value).
+ */
+const onlyTargetIdByMode = ref<{ modification?: string; target?: string }>({
+  modification: undefined,
+  target: undefined
+})
+
+/**
+ * Watchers to update the `v-model` value when modified locally.
+ */
+watch(
+  selection,
+  () => {
+    emit('update:selectionModel', selection.value)
+  },
+  { deep: true }
+)
+watch(
+  onlyTargetIdByMode,
+  () => {
+    emit('update:onlyTargetIdByModeModel', onlyTargetIdByMode.value)
+  },
+  { deep: true }
+)
+</script>
+
+<template>
+  <TabView
+    v-model:active-index="activeTabIndex"
+    :pt="{
+      nav: {
+        style: {
+          justifyContent: 'center',
+          marginBottom: '2rem',
+          fontSize: '1.25em',
+          background: `linear-gradient(white 0 0) padding-box,
+                linear-gradient(90deg,
+                  ${getColorWithOptionalShade('slate', '300')}00 10%,
+                  ${getColorWithOptionalShade('slate', '300')}   15%,
+                  ${getColorWithOptionalShade('slate', '300')}   85%,
+                  ${getColorWithOptionalShade('slate', '300')}00 90%)
+                border-box`,
+          borderStyle: 'dashed',
+          borderColor: 'white'
+        }
+      }
+    }"
+  >
+    <TabPanel header="Modification">
+      <SelectionFormModification
+        v-model:selection-model="selection.modification"
+        v-model:only-target-id="onlyTargetIdByMode.modification"
+        class="mx-auto rounded-xl border border-slate-300 bg-slate-50 p-8"
+      />
+    </TabPanel>
+    <TabPanel header="Guide">
+      <SelectionFormGuide
+        v-model:selection-model="selection.guide"
+        class="mx-auto rounded-xl border border-slate-300 bg-slate-50 p-8"
+      />
+    </TabPanel>
+    <TabPanel header="Target">
+      <SelectionFormTarget
+        v-model:selection-model="selection.target"
+        v-model:only-target-id="onlyTargetIdByMode.target"
+        class="mx-auto rounded-xl border border-slate-300 bg-slate-50 p-8"
+      />
+    </TabPanel>
+  </TabView>
+</template>
diff --git a/src/components/GuideSelectionForm.vue b/src/components/SelectionFormGuide.vue
similarity index 89%
rename from src/components/GuideSelectionForm.vue
rename to src/components/SelectionFormGuide.vue
index 061f1795a9ac70d694ccc01e3a1299c92eadfcbb..91b30aeb8410f37965de545885db9e1cdca524df 100644
--- a/src/components/GuideSelectionForm.vue
+++ b/src/components/SelectionFormGuide.vue
@@ -4,7 +4,7 @@
  */
 import { computed, ref, toRef } from 'vue'
 /**
- * Component imports
+ * Components imports
  */
 import BaseRenderedMarkdown from './BaseRenderedMarkdown.vue'
 import Chip from 'primevue/chip'
@@ -12,14 +12,18 @@ import SelectButton from 'primevue/selectbutton'
 import MultiSelect from 'primevue/multiselect'
 import { GuideClass, ModifType } from '@/gql/codegen/graphql'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
+/**
+ * Other 3rd-party imports
+ */
 import { uniqWith as _uniqWith, isEqual as _isEqual } from 'lodash-es'
 /**
  * Utils imports
  */
 import { guideSelectionQuery } from '@/gql/queries'
+import { isNonNullish } from '@/typings/typeUtils'
 
 /**
  * A guide selection.
@@ -27,6 +31,8 @@ import { guideSelectionQuery } from '@/gql/queries'
 export interface GuideSelectionModel {
   /** Currently selected guide subclasses. */
   guideSubclasses: GuideClass[]
+  /** Currently selected guide subclass labels. */
+  guideSubclassLabels: string[]
   /** Currently selected target names. */
   targetNames: string[]
   /** Currently selected modification types. */
@@ -56,6 +62,7 @@ defineEmits<{
  */
 const selection = ref<GuideSelectionModel>({
   guideSubclasses: [],
+  guideSubclassLabels: [],
   targetNames: [],
   modificationTypes: [],
   organismIds: []
@@ -67,7 +74,7 @@ const selection = ref<GuideSelectionModel>({
 const gqlQuery = useQuery({
   query: guideSelectionQuery,
   variables: toRef(() => ({
-    guideSubclasses: selection.value.guideSubclasses?.length
+    guideSubclass: selection.value.guideSubclasses?.length
       ? selection.value.guideSubclasses
       : undefined,
     targetNames: selection.value.targetNames?.length
@@ -93,6 +100,21 @@ const guideSubclassOptionsBase = computed(() =>
   }))
 )
 
+/**
+ * The guide subclasses, associated to their labels.
+ */
+const guideSubclassLabelBySubclass = computed<{
+  [guideSubclass: string]: string
+}>(() =>
+  guideSubclassOptionsBase.value.reduce(
+    (guideSubclassLabelBySubclass, guideSubclassOption) => ({
+      ...guideSubclassLabelBySubclass,
+      [guideSubclassOption.value]: guideSubclassOption.label
+    }),
+    {}
+  )
+)
+
 /**
  * Available guide subclasses, filtered based on other fields' selection (only guide
  * subclasses which exists with selected options are present).
@@ -269,7 +291,7 @@ const organismIdOptionsWithDisabling = computed(() =>
 
 <template>
   <div
-    class="grid grid-cols-[max-content_1fr] grid-rows-4 items-center gap-x-16 gap-y-8"
+    class="grid max-w-max grid-cols-[max-content_1fr] grid-rows-4 items-center gap-x-16 gap-y-8"
   >
     <h3 class="text-lg font-bold">Guide subclasses</h3>
     <SelectButton
@@ -280,7 +302,20 @@ const organismIdOptionsWithDisabling = computed(() =>
       option-disabled="isDisabled"
       multiple
       class="mr-auto"
-      @update:model-value="(selectedGuideSubclasses: GuideClass[]) => $emit('update:selectionModel', {...selection, guideSubclasses:selectedGuideSubclasses })"
+      @update:model-value="(selectedGuideSubclasses: GuideClass[]) =>
+        {
+          selection.guideSubclassLabels = selectedGuideSubclasses
+            .map((guideSubclass) =>
+              guideSubclassLabelBySubclass[guideSubclass]
+            )
+            .filter(isNonNullish)
+          $emit('update:selectionModel', {
+            ...selection,
+            guideSubclasses: selectedGuideSubclasses,
+            guideSubclassLabels: selection.guideSubclassLabels
+          })
+        }
+      "
     >
       <template #option="{ option }">
         <BaseRenderedMarkdown
@@ -305,7 +340,12 @@ const organismIdOptionsWithDisabling = computed(() =>
       :max-selected-labels="3"
       display="chip"
       filter
-      @update:model-value="(selectedTargetNames: string[]) => $emit('update:selectionModel', {...selection, targetNames:selectedTargetNames })"
+      @update:model-value="(selectedTargetNames: string[]) =>
+        $emit('update:selectionModel', {
+          ...selection,
+          targetNames: selectedTargetNames
+        })
+      "
     >
       <template #value>
         <Chip
diff --git a/src/components/ModificationSelectionForm.vue b/src/components/SelectionFormModification.vue
similarity index 98%
rename from src/components/ModificationSelectionForm.vue
rename to src/components/SelectionFormModification.vue
index 786ea2137026736a93b67adbbf33e5e51a100566..c0a2344c95fee0c7565ec5148dd1a7947a401618 100644
--- a/src/components/ModificationSelectionForm.vue
+++ b/src/components/SelectionFormModification.vue
@@ -4,7 +4,7 @@
  */
 import { computed, ref, toRef, watchEffect } from 'vue'
 /**
- * Component imports
+ * Components imports
  */
 import BaseRenderedMarkdown from './BaseRenderedMarkdown.vue'
 import Chip from 'primevue/chip'
@@ -12,9 +12,12 @@ import SelectButton from 'primevue/selectbutton'
 import MultiSelect from 'primevue/multiselect'
 import { ModifType } from '@/gql/codegen/graphql'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
+/**
+ * Other 3rd-party imports
+ */
 import { uniqWith as _uniqWith, isEqual as _isEqual } from 'lodash-es'
 /**
  * Utils imports
@@ -253,7 +256,7 @@ watchEffect(() => {
 
 <template>
   <div
-    class="grid grid-cols-[max-content_1fr] grid-rows-4 items-center gap-x-16 gap-y-8"
+    class="grid max-w-max grid-cols-[max-content_1fr] grid-rows-3 items-center gap-x-16 gap-y-8"
   >
     <h3 class="text-lg font-bold">Modification types</h3>
     <SelectButton
diff --git a/src/components/TargetSelectionForm.vue b/src/components/SelectionFormTarget.vue
similarity index 98%
rename from src/components/TargetSelectionForm.vue
rename to src/components/SelectionFormTarget.vue
index 8a7a8cbbded74ba2f63261465bd5fea98482e4d6..d22e087d57762f3e5635cbb4ef9cabbb1f4174a3 100644
--- a/src/components/TargetSelectionForm.vue
+++ b/src/components/SelectionFormTarget.vue
@@ -4,7 +4,7 @@
  */
 import { computed, ref, toRef, watchEffect } from 'vue'
 /**
- * Component imports
+ * Components imports
  */
 import BaseRenderedMarkdown from './BaseRenderedMarkdown.vue'
 import Chip from 'primevue/chip'
@@ -12,9 +12,12 @@ import SelectButton from 'primevue/selectbutton'
 import MultiSelect from 'primevue/multiselect'
 import { ModifType } from '@/gql/codegen/graphql'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
+/**
+ * Other 3rd-party imports
+ */
 import {
   uniqWith as _uniqWith,
   isEqual as _isEqual,
@@ -257,7 +260,7 @@ watchEffect(() => {
 
 <template>
   <div
-    class="grid grid-cols-[max-content_1fr] grid-rows-4 items-center gap-x-16 gap-y-8"
+    class="grid max-w-max grid-cols-[max-content_1fr] grid-rows-3 items-center gap-x-16 gap-y-8"
   >
     <h3 class="text-lg font-bold">Targets</h3>
     <MultiSelect
diff --git a/src/components/SequenceAlignment.vue b/src/components/SequenceAlignment.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3ca91569f080b2ceab57e47c77bec44a36e15cb0
--- /dev/null
+++ b/src/components/SequenceAlignment.vue
@@ -0,0 +1,986 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { computed, onMounted, ref, toRef, watch } from 'vue'
+/**
+ * Components imports
+ */
+import SequenceAlignmentToolbar from './SequenceAlignmentToolbar.vue'
+import SequenceAlignmentTrackNames from './SequenceAlignmentTrackNames.vue'
+/**
+ * Composables imports
+ */
+import { useConservationAnalysis } from '@/composables/useConservationAnalysis'
+import { useElementBounding, useResizeObserver } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
+import {
+  inRange as _inRange,
+  uniqBy as _uniqBy,
+  mapValues as _mapValues
+} from 'lodash-es'
+/**
+ * Types imports
+ */
+import type {
+  HexColorCodeModel,
+  TailwindDefaultColorNameModel
+} from '@/typings/styleTypes'
+import type { RouteLocationRaw } from 'vue-router'
+import type { StyleValue } from 'vue'
+import type { BasesConservationConfigModel } from './SequenceAlignmentToolbar.vue'
+import type { ConservationAnalysisConfigModel } from '@/composables/useConservationAnalysis'
+/**
+ * Utils imports
+ */
+import { composeConservationRate } from '@/utils/sequences'
+import { isDefined } from '@/typings/typeUtils'
+import { range } from '@/utils/numbers'
+
+/**
+ * A legend item.
+ */
+export interface LegendItemModel {
+  /** Item id. */
+  id: string
+  /** Item title. */
+  title: string
+  /** Item description. */
+  description?: string
+  /** Tailwind color name of the color to legend. */
+  color?: TailwindDefaultColorNameModel
+}
+
+/**
+ * An object on a track in an alignment.
+ */
+export interface AlignmentObjectModel {
+  /** The name of the object. */
+  name?: string
+  /** The type of the object. */
+  type?: string
+  /** The start position of the object (in the alignment reference). */
+  start: number
+  /** The end position of the object (in the alignment reference). */
+  end: number
+  /** The color in which to represent the object. */
+  color?: TailwindDefaultColorNameModel
+  /** Link to go to when clicking on the object. */
+  link?: RouteLocationRaw
+}
+
+/**
+ * An object on a track in an alignment, with the ID of the track it is on.
+ */
+export interface AlignmentObjectWithTrackIdModel extends AlignmentObjectModel {
+  /** The ID of track the object is present on. */
+  trackId: string
+}
+
+/**
+ * A track in an alignment.
+ */
+export interface AlignmentTrackModel {
+  /** The ID of the track. */
+  id: string
+  /** The name of the track. */
+  name?: string
+  /** The short name of the track. */
+  shortname?: string
+  /** The sequence of the track. */
+  sequence: string
+  /** Wether the track is a reference sequence or not. */
+  isReference?: boolean
+  /** A list of object present on the track to display. */
+  objects?: { [objectId: string]: AlignmentObjectModel }
+  /** Wether the track is an information track. */
+  isInformation?: boolean
+}
+
+/**
+ * An alignment.
+ */
+export interface AlignmentModel {
+  /** The tracks composing the alignment. */
+  tracks: AlignmentTrackModel[]
+}
+
+/**
+ * The colours for base conservation colouring.
+ */
+const BASE_CONSERVATION_COLOURS = {
+  low: '#F87171' as HexColorCodeModel,
+  middle: '#FCD34D' as HexColorCodeModel,
+  high: '#D9EDC1' as HexColorCodeModel
+}
+
+/**
+ * Component props.
+ */
+const props = defineProps<{
+  /** The representation of the alignment. */
+  alignment: AlignmentModel
+  /** The items of the legend to display for the highlighted groups. */
+  legendItems?: LegendItemModel[]
+}>()
+
+/**
+ * Size (in term of nucl.) of the groups into which the sequences are divided.
+ */
+const nucleotideGroupsSize = ref(10)
+
+/**
+ * Number of groups in which the sequences are divided.
+ */
+const nucleotideGroupsCount = computed(() =>
+  Math.ceil(
+    (props.alignment.tracks[0]?.sequence.length || 1) /
+      nucleotideGroupsSize.value
+  )
+)
+
+/**
+ * Number of nucleotides in the last group.
+ */
+const lastNucleotideGroupSize = computed(
+  () =>
+    (props.alignment.tracks[0]?.sequence.length || 1) %
+    nucleotideGroupsSize.value
+)
+
+/**
+ * The tracks, with an additional track for the conservation analysis added
+ * at the end.
+ */
+const tracksWithConservationTrack = computed(() => [
+  ...props.alignment.tracks,
+  conservationAnalysis.track.value
+])
+
+/**
+ * The sequences of the alignment, split and rearranged in the following nested
+ * arrays structure:
+ * ```ts
+ *  [
+ *    [ // Group 0
+ *      [ // Nucleotide 0
+ *        sequence1[0],
+ *        sequence2[0],
+ *        ...,
+ *        sequence<#ofTracks>[0]
+ *      ],
+ *      [ // Nucleotide 1
+ *        sequence1[1],
+ *        sequence2[1],
+ *        ...,
+ *        sequence<#ofTracks>[1]
+ *      ],
+ *      ...,
+ *      [ // Last nucleotide of group 0
+ *        sequence1[nucleotideGroupsSize - 1],
+ *        sequence2[nucleotideGroupsSize - 1],
+ *        ...,
+ *        sequence<#ofTracks>[nucleotideGroupsSize - 1]
+ *      ],
+ *    ],
+ *    [ // Group 1
+ *      [ // First nucleotide of group 1
+ *        sequence1[nucleotideGroupsSize],
+ *        sequence2[nucleotideGroupsSize],
+ *        ...,
+ *        sequence<#ofTracks>[nucleotideGroupsSize]
+ *      ],
+ *      [
+ *        sequence1[nucleotideGroupsSize + 1],
+ *        sequence2[nucleotideGroupsSize + 1],
+ *        ...,
+ *        sequence<#ofTracks>[nucleotideGroupsSize + 1]
+ *      ],
+ *      ...,
+ *      [ // Last nucleotide of group 1
+ *        sequence1[2 * nucleotideGroupsSize - 1],
+ *        sequence2[2 * nucleotideGroupsSize - 1],
+ *        ...,
+ *        sequence<#ofTracks>[2 * nucleotideGroupsSize - 1]
+ *      ],
+ *    ],
+ *    ...
+ *  ]
+ * ```
+ */
+const splitAlignmentSequences = computed(() =>
+  // Top-level array, size = group count, one cell = one group
+  Array.from({ length: nucleotideGroupsCount.value }, (_, groupIndex) =>
+    // Second-level array, size = group size (if last group, special size), one
+    // cell = one position in alignment
+    Array.from(
+      {
+        length:
+          groupIndex === nucleotideGroupsCount.value - 1
+            ? lastNucleotideGroupSize.value
+            : nucleotideGroupsSize.value
+      },
+      (_, nucleotideIndexInGroup) => {
+        // Compute the position of the nucleotide
+        const nucleotideIndex =
+          groupIndex * nucleotideGroupsSize.value + nucleotideIndexInGroup
+        // Third-level array, size = # of sequences, one cell = the nucleotide
+        // at current position in the corresponding sequence
+        return Array.from(
+          { length: tracksWithConservationTrack.value.length },
+          (_, sequenceIndex) => {
+            const nucleotide =
+              tracksWithConservationTrack.value[sequenceIndex]?.sequence[
+                nucleotideIndex
+              ]
+            return nucleotide ? nucleotide : '-'
+          }
+        )
+      }
+    )
+  )
+)
+
+/**
+ * Wether a nucleotide is in a given object of a given track or not.
+ * @param trackIndex The index of the track in the alignment.
+ * @param position The position of the nucleotide to check.
+ * @param objectId The id of the object to check for.
+ * @returns `true` if position if in the given object, `false` otherwise.
+ */
+const isInObject = (
+  trackIndex: number,
+  position: number,
+  objectId: string
+): boolean => {
+  const object =
+    tracksWithConservationTrack.value[trackIndex]?.objects?.[objectId]
+  return !!object && _inRange(position, object.start, object.end + 1)
+}
+
+/**
+ * Gets the IDs of the objects of a given track containing a nucleotide.
+ * @param trackIndex The index of the track in the alignment.
+ * @param position The position of the nucleotide for which to get object IDs.
+ * @returns A list of the IDs of the objects containing the nucleotide.
+ */
+const objectIdsContaining = (
+  trackIndex: number,
+  position: number
+): string[] => {
+  const trackObjects = tracksWithConservationTrack.value[trackIndex]?.objects
+  return trackObjects
+    ? Object.keys(trackObjects).filter((objectId) =>
+        isInObject(trackIndex, position, objectId)
+      )
+    : []
+}
+
+/**
+ * Whether a nucleotide is in any object of a given track.
+ * @param trackIndex The index of the track in the alignment.
+ * @param position The position of the nucleotide to check.
+ * @returns `true` if the nucleotide is in any object, `false` otherwise.
+ */
+const isInAnyObject = (trackIndex: number, position: number): boolean =>
+  !!objectIdsContaining(trackIndex, position).length
+
+/**
+ * For each track, a `Set` of the boundary positions (start & end) of all
+ * objects. It is in the form of an array, indexed in the same order as the
+ * tracks in the alignment.
+ */
+const objectsBoundaryPositions = computed(() =>
+  tracksWithConservationTrack.value.map((track) => {
+    // Objects present on the current track
+    const trackObjects =
+      track.isInformation && track.objects
+        ? Object.values(track.objects)
+        : referenceTrackModifications.value.filter(
+            (modification) => modification.trackId === track.id
+          )
+    return trackObjects.reduce(
+      (objectsBoundaryPositions, object) =>
+        object.start && object.end
+          ? objectsBoundaryPositions.add(object.start).add(object.end)
+          : objectsBoundaryPositions,
+      new Set<number>()
+    )
+  })
+)
+
+/**
+ * Whether a nucleotide is a boundary position (start or end) of an object.
+ * @param position The position of the nucleotide to check.
+ * @returns `true` if the nucleotide is the start of an object, `false` otherwise.
+ */
+const isObjectBoundary = (trackIndex: number, position: number): boolean =>
+  !!objectsBoundaryPositions.value[trackIndex]?.has(position)
+
+/**
+ * Composes the Tailwind color name in which to paint a nucleotide based on its
+ * position.
+ * @param trackIndex The index of the track in the alignment.
+ * @param position The position for which to compose the color.
+ * @returns `slate` if there is no or several objects at the given position, the
+ * Tailwind color name of the object if there is only one.
+ */
+const composeInObjectPositionColor = (
+  trackIndex: number,
+  position: number
+): TailwindDefaultColorNameModel => {
+  const objectIds = objectIdsContaining(trackIndex, position)
+  // If only one group, use its color, otherwise, use 'slate'
+  return objectIds.length === 1 && objectIds[0]
+    ? tracksWithConservationTrack.value[trackIndex]?.objects?.[objectIds[0]]
+        ?.color || 'slate'
+    : 'slate'
+}
+
+/**
+ * Sequence container DOM `HTMLElement`.
+ */
+const sequenceContainerElement = ref<HTMLElement>()
+/**
+ * Split sequences groups DOM `HTMLElement` array.
+ */
+const sequenceGroupElements = ref<HTMLElement[]>([])
+/**
+ * First & last nucleotides of each box DOM `HTMLElement` array.
+ */
+const boxBoundaryElements = ref<HTMLElement[]>([])
+
+/**
+ * Bounding box of the first split sequences group DOM `HTMLElement`.
+ */
+const firstSequenceGroupElementBounding = useElementBounding(
+  toRef(() => sequenceGroupElements.value[0])
+)
+
+/**
+ * Bounding box of the split sequences groups DOM `HTMLElements`.
+ */
+const sequenceContainerElementBounding = useElementBounding(
+  sequenceContainerElement
+)
+
+/**
+ * Number of sequence lines.
+ */
+const lineCount = computed(() => {
+  const firstSequenceGroupElement = sequenceGroupElements.value[0]
+  return (
+    (firstSequenceGroupElement &&
+      Math.round(
+        sequenceContainerElementBounding.height.value /
+          (parseInt(
+            window.getComputedStyle(firstSequenceGroupElement).marginTop
+          ) +
+            firstSequenceGroupElementBounding.height.value)
+      )) ||
+    1
+  )
+})
+
+/**
+ *  Height of a sequence line.
+ */
+const lineHeight = computed(
+  () =>
+    firstSequenceGroupElementBounding.bottom.value -
+    sequenceContainerElementBounding.top.value
+)
+
+/**
+ * Dictionary of the number of line on which each object spreads,
+ * by group ID.
+ */
+const tracksObjectsLineCount = ref<
+  ({ [groupId: string]: number | undefined } | undefined)[]
+>([])
+
+/**
+ * Updates the number of line on which each object spreads.
+ * @returns The updated number of line on which each object spreads.
+ * @description Retrieves the line count by getting the difference between the
+ * top of the last nucleotide of the box and the top of the first one, and
+ * dividing by the line height.
+ */
+const updateObjectsLineCount = () =>
+  (tracksObjectsLineCount.value = tracksWithConservationTrack.value.map(
+    (track, trackIndex) =>
+      _mapValues(track.objects, (trackObject) => {
+        const objectStartNucleotideElementParent =
+          boxBoundaryElements.value.find(
+            (element) =>
+              element.dataset.trackAndPosition ===
+              `${trackIndex}:${trackObject.start}`
+          )?.offsetParent
+
+        const objectEndNucleotideElementParent = boxBoundaryElements.value.find(
+          (element) =>
+            element.dataset.trackAndPosition ===
+            `${trackIndex}:${trackObject.end}`
+        )?.offsetParent
+
+        if (
+          !(
+            objectStartNucleotideElementParent instanceof HTMLElement &&
+            objectEndNucleotideElementParent instanceof HTMLElement &&
+            objectStartNucleotideElementParent.offsetParent instanceof
+              HTMLElement &&
+            objectEndNucleotideElementParent.offsetParent instanceof HTMLElement
+          )
+        ) {
+          return undefined
+        }
+
+        return (
+          lineHeight.value &&
+          Math.round(
+            (objectEndNucleotideElementParent.offsetParent.offsetTop -
+              objectStartNucleotideElementParent.offsetParent.offsetTop) /
+              lineHeight.value
+          ) + 1
+        )
+      })
+  ))
+
+/**
+ * Width of the sequence container.
+ */
+const sequenceContainerContentWidth = ref<number>()
+
+/**
+ * Updates the width of the sequence container.
+ */
+const updateSequenceContainerContentWidth =
+  (): typeof sequenceContainerContentWidth.value => {
+    // First sequence group DOM element
+    const firstSequenceGroupElement = sequenceGroupElements.value[0]
+    if (!firstSequenceGroupElement) return
+
+    // Size of the right margin of a sequence group DOM element
+    const sequenceGroupElementRightMargin = parseInt(
+      window.getComputedStyle(firstSequenceGroupElement).marginRight
+    )
+    if (!sequenceGroupElementRightMargin) return
+
+    // Width of a sequence group DOM element
+    const sequenceGroupElementWidth =
+      firstSequenceGroupElement.offsetWidth + sequenceGroupElementRightMargin
+    if (!sequenceGroupElementWidth) return
+
+    // Width of the sequences container DOM element
+    const sequenceContainerElementWidth =
+      sequenceContainerElement.value?.offsetWidth
+    if (!sequenceContainerElementWidth) return
+
+    // Sequence content width = container width - (space not actually occupied by
+    // sequence + 1 * right margin of a sequence group)
+    return (sequenceContainerContentWidth.value =
+      sequenceContainerElementWidth -
+      ((sequenceContainerElementWidth % sequenceGroupElementWidth) +
+        sequenceGroupElementRightMargin))
+  }
+
+/**
+ * Updates all non-reactive values.
+ */
+const update = (): void => {
+  updateObjectsLineCount()
+  updateSequenceContainerContentWidth()
+}
+
+/**
+ * Sets hook to update non-reactive values on component mount.
+ */
+onMounted(update)
+
+/**
+ * Sets an observer to update on container resize.
+ */
+useResizeObserver(sequenceContainerElement, update)
+
+/**
+ * Reactive array, for each track, the style to apply to each fragment of each
+ * of its objects.
+ */
+const boxStyles = computed(() =>
+  // Map tracks
+  tracksWithConservationTrack.value.map((track, trackIndex) => {
+    // No object on current track
+    if (!track.objects) {
+      return {}
+    }
+
+    // Map track objects to the style of each of their fragment
+    return _mapValues(track.objects, (trackObject, trackObjectId) => {
+      // DOM element of the first nucleotide of the box
+      const objectStartNucleotideElementParent = boxBoundaryElements.value.find(
+        (element) =>
+          element.dataset.trackAndPosition ===
+          `${trackIndex}:${trackObject.start}`
+      )?.offsetParent
+
+      // DOM element of the last nucleotide of the box
+      const objectEndNucleotideElementParent = boxBoundaryElements.value.find(
+        (element) =>
+          element.dataset.trackAndPosition ===
+          `${trackIndex}:${trackObject.end}`
+      )?.offsetParent
+
+      if (
+        !(
+          objectStartNucleotideElementParent instanceof HTMLElement &&
+          objectEndNucleotideElementParent instanceof HTMLElement &&
+          objectStartNucleotideElementParent.offsetParent instanceof
+            HTMLElement &&
+          objectEndNucleotideElementParent.offsetParent instanceof HTMLElement
+        )
+      ) {
+        return
+      }
+
+      // Absolute positions of the first and last nucleotide of the object DOM
+      // elements
+      const objectStartNucleotideElementTop =
+        objectStartNucleotideElementParent.offsetParent.offsetTop +
+        (objectStartNucleotideElementParent?.offsetTop || 0)
+      const objectStartNucleotideElementLeft =
+        objectStartNucleotideElementParent.offsetParent.offsetLeft +
+        (objectStartNucleotideElementParent?.offsetLeft || 0)
+      const objectEndNucleotideElementLeft =
+        objectEndNucleotideElementParent.offsetParent.offsetLeft +
+        (objectEndNucleotideElementParent?.offsetLeft || 0)
+      const objectEndNucleotideElementRight =
+        objectEndNucleotideElementLeft +
+        (objectEndNucleotideElementParent?.offsetWidth || 0)
+
+      // Number of fragment in which the current object is divided
+      const boxFragmentCount =
+        tracksObjectsLineCount.value?.[trackIndex]?.[trackObjectId] || 0
+
+      // Array of length equals # of fragments, containing style for each of them
+      return Array.from(
+        { length: boxFragmentCount },
+        (_, fragmentIndex): StyleValue => ({
+          top: `${
+            objectStartNucleotideElementTop +
+            fragmentIndex * (lineHeight.value || 0)
+          }px`,
+          left:
+            fragmentIndex === 0
+              ? `calc(${objectStartNucleotideElementLeft}px - 0.125rem)`
+              : '0',
+          right: `calc(${
+            (sequenceContainerElementBounding.width.value || 0) -
+            (fragmentIndex === boxFragmentCount - 1
+              ? objectEndNucleotideElementRight
+              : sequenceContainerContentWidth.value || 0)
+          }px - 0.125rem)`
+        })
+      )
+    })
+  })
+)
+
+/**
+ * Compute the position of a nucleotide in the reference of a sequence from the
+ * position on the same sequence gapped with `-` for alignment.
+ * @param alignedSequence The sequence, gapped with `-` for alignment with other
+ * sequences.
+ * @param inAlignmentPosition The position in the reference of the alignment to
+ * convert to the source sequence reference (starts at 1).
+ */
+const composePositionOnSource = (
+  alignedSequence: string,
+  inAlignmentPosition: number
+): number | undefined =>
+  alignedSequence[inAlignmentPosition - 1] === '-'
+    ? undefined
+    : inAlignmentPosition -
+      (alignedSequence.slice(0, inAlignmentPosition).split('-').length - 1)
+
+/**
+ * Compute the position of a nucleotide on a sequence gapped with `-` for
+ * alignment from the position in the source reference of the same sequence.
+ * @param alignedSequence The sequence, gapped with `-` for alignment with other
+ * sequences.
+ * @param inSourcePosition The position in the source sequence reference to
+ * convert to the reference of the alignment (starts at 1).
+ * @returns The position of the nucleotide on the aligned sequence, -1 if the
+ * requested position exceeded the actual length of the source sequence.
+ */
+const composePositionOnAlignment = (
+  alignedSequence: string,
+  inSourcePosition: number
+): number => {
+  const firstDashPositionOnAlignment = alignedSequence.indexOf('-') + 1
+
+  // If the aligned sequence is shorter than the requested position, it means
+  // that the latter doesn't exists.
+  if (alignedSequence.length < inSourcePosition) {
+    return -1
+  }
+
+  // If the requested position is closer to the start than the first dash (or if
+  // there is no dash in it), then the position on the alignment is the same
+  // than on the source sequence.
+  if (
+    inSourcePosition < firstDashPositionOnAlignment ||
+    firstDashPositionOnAlignment === 0
+  ) {
+    return inSourcePosition
+  }
+
+  // Otherwise, remove the part to the first dash and compute the position on
+  // the remaining aligned sequence (& handle case were the position doesn't
+  // exists).
+  const positionOnRemainingAlignment = composePositionOnAlignment(
+    alignedSequence.slice(firstDashPositionOnAlignment),
+    inSourcePosition - firstDashPositionOnAlignment - 1
+  )
+  return positionOnRemainingAlignment === -1
+    ? -1
+    : positionOnRemainingAlignment + firstDashPositionOnAlignment
+}
+
+/**
+ * Maximum width of the names of the tracks DOM `HTMLElements`.
+ */
+const trackNamesWidth = ref<number>(0)
+
+/**
+ * Width of the container element of the track names, express as a ratio to
+ * apply on the width of the sequence group elements (e.g., if it is 3, this
+ * means that the container element of the track names should be 3 times wider
+ * than a sequence group element).
+ */
+const trackNamesContainerWidthRatio = computed(() =>
+  Math.ceil(
+    trackNamesWidth.value / (firstSequenceGroupElementBounding.width.value || 1)
+  )
+)
+
+/**
+ * Configuration for the bases conservation colouring.
+ */
+const basesConservationConfig = ref<BasesConservationConfigModel>({
+  isEnabled: false,
+  thresholds: { low: 0.25, high: 0.75 }
+})
+
+/**
+ * Computes the conservation rate of the reference nucleotide in the provided
+ * nucl. list, and derivates from it the colour to use for the background.
+ * @param nucleotides The list of nucleotides on which to compute the
+ *                    conservation colour.
+ * @param referenceNucleotide The nucleotide for which  to compute the
+ *                            conservation colour.
+ * @returns The colour in which to set the background according to the
+ *          computed conservation rate.
+ */
+const composeConservationColour = (
+  nucleotides: string[],
+  referenceNucleotide: string
+): string => {
+  const conservationRate = composeConservationRate(
+    nucleotides,
+    referenceNucleotide
+  )
+  if (conservationRate > basesConservationConfig.value.thresholds.high) {
+    return BASE_CONSERVATION_COLOURS.high
+  }
+  if (conservationRate > basesConservationConfig.value.thresholds.low) {
+    return BASE_CONSERVATION_COLOURS.middle
+  }
+  return BASE_CONSERVATION_COLOURS.low
+}
+
+/**
+ * All the modifications present on the reference track sequences.
+ */
+const referenceTrackModifications = computed<AlignmentObjectWithTrackIdModel[]>(
+  () =>
+    props.alignment.tracks
+      .filter((track) => track.isReference)
+      .map(
+        (track) =>
+          track.objects &&
+          Object.values(track.objects).map((object) => ({
+            ...object,
+            trackId: track.id
+          }))
+      )
+      .flat()
+      .filter(isDefined)
+)
+
+/**
+ * Available options for track selection for conservation analysis.
+ */
+const conservationAnalysisTrackOptions = computed(() =>
+  props.alignment.tracks
+    .filter((track) => track.isReference && !track.isInformation)
+    .map((track) => ({
+      label: track.name || track.id,
+      id: track.id
+    }))
+)
+
+/**
+ * A list of the types of the objects present on the sequences of the alignment.
+ */
+const conservationAnalysisObjectTypeOptions = computed(() =>
+  _uniqBy(
+    Array.from(
+      props.alignment.tracks
+        .filter((track) =>
+          conservationAnalysisConfig.value.trackIds.includes(track.id)
+        )
+        .map(
+          (track) =>
+            track.objects &&
+            Object.values(track.objects).map((object) =>
+              object.type === undefined
+                ? undefined
+                : { label: object.type, type: object.type }
+            )
+        )
+        .flat()
+        .filter(isDefined)
+    ),
+    'type'
+  )
+)
+
+/**
+ * Configuration for the conservation analysis.
+ */
+const conservationAnalysisConfig = ref<ConservationAnalysisConfigModel>({
+  trackIds: [],
+  objectTypes: [],
+  analysisType: null
+})
+
+/**
+ * Update non-reactive values when config changes.
+ */
+watch(conservationAnalysisConfig, () => {
+  setTimeout(update, 100)
+})
+
+/**
+ * Conservation analysis, reactively updated when analysis parameters change.
+ */
+const conservationAnalysis = useConservationAnalysis(
+  props.alignment.tracks,
+  conservationAnalysisConfig
+)
+
+/**
+ * Wether a conservation analysis is displayed or not.
+ */
+const isConservationAnalysisDisplayed = computed(
+  () => conservationAnalysisConfig.value.analysisType !== null
+)
+
+/**
+ * The value to apply to the conservation analysis track `display` CSS property.
+ */
+const conservationAnalysisTrackDisplay = computed(() => ({
+  trackLabel: isConservationAnalysisDisplayed.value ? 'flex' : 'none',
+  trackSequence: isConservationAnalysisDisplayed.value ? undefined : 'none'
+}))
+</script>
+
+<template>
+  <SequenceAlignmentToolbar
+    v-model:nucleotide-groups-size-model="nucleotideGroupsSize"
+    v-model:bases-conservation-config-model="basesConservationConfig"
+    v-model:conservation-analysis-config-model="conservationAnalysisConfig"
+    :bases-conservation-colours="BASE_CONSERVATION_COLOURS"
+    :conservation-analysis-track-options="conservationAnalysisTrackOptions"
+    :conservation-analysis-object-type-options="
+      conservationAnalysisObjectTypeOptions
+    "
+  />
+
+  <div
+    class="mt-8 grid gap-4 text-2xl leading-[normal]"
+    :style="{
+      gridTemplateColumns: `${
+        trackNamesContainerWidthRatio * nucleotideGroupsSize * 1.5
+      }rem 1fr`
+    }"
+  >
+    <!-- Track names -->
+    <div>
+      <SequenceAlignmentTrackNames
+        v-model:track-names-width-model="trackNamesWidth"
+        :tracks="tracksWithConservationTrack"
+      />
+      <SequenceAlignmentTrackNames
+        v-for="line in range(lineCount - 1)"
+        :key="line"
+        :tracks="tracksWithConservationTrack"
+      />
+    </div>
+
+    <div ref="sequenceContainerElement" class="relative">
+      <!-- Track content -->
+      <span
+        v-for="(sequenceGroup, groupIndex) in splitAlignmentSequences"
+        :key="groupIndex"
+        ref="sequenceGroupElements"
+        :data-group-index="groupIndex"
+        class="relative z-10 mr-4 mt-8 inline-block select-none whitespace-nowrap font-mono"
+        :style="{ width: `${nucleotideGroupsSize * 1.5}rem` }"
+      >
+        <span class="absolute -top-4 left-0 select-none text-sm text-slate-400">
+          {{ groupIndex * nucleotideGroupsSize + 1 }}
+        </span>
+        <span
+          v-for="(nucleotide, nucleotideIndexInGroup) in sequenceGroup"
+          :key="groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup"
+          :data-nucleotide-index="
+            groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup
+          "
+          class="inline-flex flex-col"
+        >
+          <span
+            v-for="(trackNucleotide, trackIndex) in nucleotide"
+            :key="`${trackIndex}:${
+              groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup
+            }`"
+            v-tooltip.top="{
+              value:
+                composePositionOnSource(
+                  alignment.tracks[trackIndex]?.sequence || '',
+                  groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup + 1
+                )?.toString() || '<em>N/A</em>',
+              pt: {
+                text: {
+                  style: { textAlign: 'center', fontWeight: '600' }
+                }
+              },
+              escape: true,
+              autoHide: false
+            }"
+            :class="[
+              'relative mx-[.0625rem] cursor-help border-2 border-transparent px-0.5 pt-0.5',
+              {
+                'rounded-t-md': trackIndex === 0,
+                'rounded-b-md':
+                  trackIndex === props.alignment.tracks.length - 1,
+                'conservation-track-sequence':
+                  tracksWithConservationTrack[trackIndex]?.isInformation
+              },
+              isInAnyObject(
+                trackIndex,
+                groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup + 1
+              ) && [
+                `text-${composeInObjectPositionColor(
+                  trackIndex,
+                  groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup + 1
+                )}-600`,
+                'modification font-semibold'
+              ]
+            ]"
+            :style="
+              (basesConservationConfig.isEnabled &&
+                trackNucleotide !== '-' &&
+                !tracksWithConservationTrack[trackIndex]?.isInformation && {
+                  backgroundColor: composeConservationColour(
+                    nucleotide,
+                    trackNucleotide
+                  )
+                }) ||
+              undefined
+            "
+          >
+            <span
+              v-if="
+                isObjectBoundary(
+                  trackIndex,
+                  groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup + 1
+                )
+              "
+              ref="boxBoundaryElements"
+              :data-track-and-position="`${trackIndex}:${
+                groupIndex * nucleotideGroupsSize + nucleotideIndexInGroup + 1
+              }`"
+            >
+              {{ trackNucleotide }}
+            </span>
+            <span v-else>
+              {{ trackNucleotide }}
+            </span>
+          </span>
+        </span>
+      </span>
+
+      <!-- Object boxes -->
+      <span
+        v-for="(track, trackIndex) in tracksWithConservationTrack"
+        :key="track.id"
+      >
+        <span
+          v-for="[objectId, object] in Object.entries(track.objects || {})"
+          :key="objectId"
+          class="object"
+        >
+          <span
+            v-for="fragmentIndex in range(
+              tracksObjectsLineCount?.[trackIndex]?.[objectId] || 0
+            )"
+            :key="fragmentIndex"
+            :style="boxStyles?.[trackIndex]?.[objectId]?.[fragmentIndex]"
+            :class="[
+              'object-fragment absolute z-10 h-8 border-y-2 bg-opacity-50 px-0.5 text-2xl mix-blend-multiply',
+              [`!border-${object.color}-600`, `bg-${object.color}-100`],
+              {
+                'rounded-l-xl border-l-2': fragmentIndex === 0,
+                'rounded-r-xl border-r-2':
+                  tracksObjectsLineCount &&
+                  fragmentIndex + 1 ===
+                    tracksObjectsLineCount[trackIndex]?.[objectId]
+              }
+            ]"
+          />
+        </span>
+      </span>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.conservation-track-label {
+  display: v-bind('conservationAnalysisTrackDisplay.trackLabel');
+}
+
+.conservation-track-sequence {
+  display: v-bind('conservationAnalysisTrackDisplay.trackSequence');
+}
+
+.track-name-arrow {
+  &::before {
+    // Custom dashed border
+    border-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAACCAYAAABllJ3tAAAATUlEQVQIHQFCAL3/AZSjuP8AAAAAAAAAAAAAAABsXUgBAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7aYEBI+Q3/YAAAAASUVORK5CYII=')
+      2 0 0 / 1 1 0 repeat;
+  }
+  &::after {
+    background: rgb(255, 255, 255);
+    background: linear-gradient(
+      45deg,
+      rgba(255, 255, 255, 0) 0%,
+      rgba(255, 255, 255, 0) 50%,
+      rgba(255, 255, 255, 1) 50%,
+      rgba(255, 255, 255, 1) 100%
+    );
+  }
+}
+</style>
diff --git a/src/components/SequenceAlignmentToolbar.vue b/src/components/SequenceAlignmentToolbar.vue
new file mode 100644
index 0000000000000000000000000000000000000000..25228b1219f853b06cb879481caf75dad8520934
--- /dev/null
+++ b/src/components/SequenceAlignmentToolbar.vue
@@ -0,0 +1,586 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { ref, watch } from 'vue'
+/**
+ * Component imports
+ */
+import BaseRenderedMarkdown from './BaseRenderedMarkdown.vue'
+import Toolbar from 'primevue/toolbar'
+import Dropdown from 'primevue/dropdown'
+import TabView from 'primevue/tabview'
+import TabPanel from 'primevue/tabpanel'
+import Slider, { type SliderSlideEndEvent } from 'primevue/slider'
+import MultiSelect from 'primevue/multiselect'
+import SelectButton from 'primevue/selectbutton'
+import ToggleButton from 'primevue/togglebutton'
+import IconFa6RegularCircleQuestion from '~icons/fa6-regular/circle-question'
+
+/**
+ * Types imports.
+ */
+import type { HexColorCodeModel } from '@/typings/styleTypes'
+import {
+  ConservationAnalysisTypesEnum,
+  type ConservationAnalysisConfigModel
+} from '@/composables/useConservationAnalysis'
+
+/**
+ * Configuration for the bases conservation colouring.
+ */
+export interface BasesConservationConfigModel {
+  /** Wether the bases conservation colouring is enabled. */
+  isEnabled: boolean
+  /** Conservation rate thresholds for bases conservation colouring. */
+  thresholds: {
+    low: number
+    high: number
+  }
+}
+
+/**
+ * Available options for conservation analysis type.
+ */
+const CONSERVATION_ANALYSIS_TYPES_OPTIONS = [
+  {
+    label: 'Specific',
+    analysisType: ConservationAnalysisTypesEnum.Specific
+  },
+  {
+    label: 'Common',
+    analysisType: ConservationAnalysisTypesEnum.Common
+  }
+]
+
+/**
+ * Component props.
+ */
+const props = withDefaults(
+  defineProps<{
+    /** The selected nucleotide group size. */
+    nucleotideGroupsSizeModel: number
+    /** The config for the bases conservation colouring. */
+    basesConservationConfigModel: BasesConservationConfigModel
+    /** Colours to use for bases conservation colouring */
+    basesConservationColours?: {
+      low: HexColorCodeModel
+      middle: HexColorCodeModel
+      high: HexColorCodeModel
+    }
+    /** The config for the conservation analysis. */
+    conservationAnalysisConfigModel: ConservationAnalysisConfigModel
+    /** Available options for track selection for conservation analysis. */
+    conservationAnalysisTrackOptions: { label: string; id: string }[]
+    /** Available options for selection of the types of the objects present on
+     * the sequences for conservation analysis. */
+    conservationAnalysisObjectTypeOptions: { label?: string; type: string }[]
+  }>(),
+  {
+    basesConservationColours: () => ({
+      low: '#F87171' as HexColorCodeModel,
+      middle: '#FCD34D' as HexColorCodeModel,
+      high: '#D9EDC1' as HexColorCodeModel
+    })
+  }
+)
+
+const emit = defineEmits<{
+  /** Event used to update the `v-model:nucleotideGroupsSizeModel` value. */
+  'update:nucleotideGroupsSizeModel': [nucleotideGroupsSizeModel: number]
+  /** Event used to update the `v-model:basesConservationConfigModel` value. */
+  'update:basesConservationConfigModel': [
+    basesConservationConfigModel: BasesConservationConfigModel
+  ]
+  /** Event used to update the `v-model:conservationAnalysisConfigModel` value. */
+  'update:conservationAnalysisConfigModel': [
+    conservationAnalysisConfigModel: ConservationAnalysisConfigModel
+  ]
+}>()
+
+/**
+ * The currently active tab.
+ */
+const activeTabIndex = ref(0)
+
+/**
+ * Clears the conservation analysis type if no track or modification type is
+ * selected anymore for conservation analysis.
+ */
+const clearAnalysisTypeIfNeeded = () => {
+  if (
+    props.conservationAnalysisConfigModel.objectTypes.length === 0 ||
+    props.conservationAnalysisConfigModel.trackIds.length === 0
+  ) {
+    emit('update:conservationAnalysisConfigModel', {
+      ...props.conservationAnalysisConfigModel,
+      analysisType: null
+    })
+  }
+}
+
+/**
+ * Callbacks to use for events in template.
+ */
+const eventHandlers = {
+  /** Callbacks for values related to bases conservation colouring. */
+  basesConservation: {
+    /** Callback for the toggling of bases conservation colouring. */
+    isEnabled: (newValue: boolean) =>
+      emit('update:basesConservationConfigModel', {
+        ...props.basesConservationConfigModel,
+        isEnabled: newValue
+      }),
+    /** Callback for bases conservation colouring low threshold update by slider. */
+    lowThreshold: (slideEndEvent: SliderSlideEndEvent) => {
+      emit('update:basesConservationConfigModel', {
+        ...props.basesConservationConfigModel,
+        thresholds: {
+          ...props.basesConservationConfigModel.thresholds,
+          low: slideEndEvent.value
+        }
+      })
+    },
+    /** Callback for bases conservation colouring high threshold update by slider. */
+    highThreshold: (slideEndEvent: SliderSlideEndEvent) => {
+      emit('update:basesConservationConfigModel', {
+        ...props.basesConservationConfigModel,
+        thresholds: {
+          ...props.basesConservationConfigModel.thresholds,
+          high: slideEndEvent.value
+        }
+      })
+    }
+  },
+  /** Callbacks for values related to conservation analysis. */
+  conservationAnalysis: {
+    /** Callback for track IDs selection update in Multiselect. */
+    trackIds: (newValue: string[]) => {
+      clearAnalysisTypeIfNeeded()
+      emit('update:conservationAnalysisConfigModel', {
+        ...props.conservationAnalysisConfigModel,
+        trackIds: newValue
+      })
+    },
+    /** Callback for object types selection update in Multiselect. */
+    objectTypes: (newValue: string[]) => {
+      clearAnalysisTypeIfNeeded()
+      emit('update:conservationAnalysisConfigModel', {
+        ...props.conservationAnalysisConfigModel,
+        objectTypes: newValue
+      })
+    },
+    /** Callback for object types selection update in Multiselect. */
+    analysisType: (newValue: ConservationAnalysisTypesEnum) => {
+      emit('update:conservationAnalysisConfigModel', {
+        ...props.conservationAnalysisConfigModel,
+        analysisType: newValue
+      })
+    }
+  }
+}
+
+/**
+ * Local values of the thresholds for bases conservation colouring, to use as
+ * `v-model` for the sliders.
+ *
+ * @description We use this instead of
+ * {@link props.basesConservationConfigModel.thresholds} directly because
+ * sliders update their value immediately, but we only wan't to update the
+ * actual thresholds when mouse is released (on `slideend` event).
+ * Thus, those intermediary values allow displaying the new threshold in real
+ * time, but only updating the actual value when the mouse is released.
+ */
+const localBasesConservationThresholds = ref({
+  ...props.basesConservationConfigModel.thresholds
+})
+
+/**
+ * Watcher to update the local value of the thresholds for bases conservation
+ * colouring when actual thresholds are updated using `v-model`.
+ */
+watch(
+  () => props.basesConservationConfigModel.thresholds,
+  () =>
+    (localBasesConservationThresholds.value = {
+      ...props.basesConservationConfigModel.thresholds
+    })
+)
+</script>
+
+<template>
+  <Toolbar
+    :pt="{
+      start: {
+        style: {
+          gap: '2rem',
+          alignItems: 'stretch'
+        }
+      }
+    }"
+    class="mx-auto w-5/6"
+  >
+    <template #start>
+      <label class="flex flex-col gap-2 text-sm">
+        Group length
+        <div class="flex grow flex-col justify-center">
+          <Dropdown
+            :model-value="nucleotideGroupsSizeModel"
+            :options="[5, 10, 20]"
+            class="w-52"
+            @update:model-value="
+              (newValue: number) => $emit('update:nucleotideGroupsSizeModel', newValue)
+            "
+          >
+            <template #option="{ option }">{{ option }} nucleotides</template>
+            <template #value="{ value }">{{ value }} nucleotides</template>
+          </Dropdown>
+        </div>
+      </label>
+
+      <!-- <div class="self-stretch rounded border border-slate-200" /> -->
+    </template>
+
+    <template #center>
+      <TabView
+        v-model:active-index="activeTabIndex"
+        :pt="{
+          nav: {
+            style: {
+              background: 'none',
+              justifyContent: 'center'
+            }
+          },
+          panelContainer: {
+            style: {
+              background: 'none'
+            }
+          }
+        }"
+      >
+        <TabPanel
+          header="Bases conservation"
+          :pt="{
+            headerAction: {
+              style: {
+                background: 'none'
+              }
+            }
+          }"
+        >
+          <div class="flex flex-wrap gap-8">
+            <div class="flex flex-col gap-2">
+              <label
+                for="sequence-conservation-colouring-switch"
+                class="text-sm"
+              >
+                Conservation colouring
+              </label>
+              <div class="flex grow flex-col justify-center">
+                <ToggleButton
+                  :model-value="basesConservationConfigModel.isEnabled"
+                  on-label="On"
+                  off-label="Off"
+                  class="w-full"
+                  input-id="sequence-conservation-colouring-switch"
+                  @update:model-value="
+                    eventHandlers.basesConservation.isEnabled
+                  "
+                />
+              </div>
+            </div>
+
+            <label class="flex flex-col gap-2 text-sm">
+              Conservation thresholds
+              <div class="flex grow flex-col justify-center">
+                <div
+                  v-tooltip.bottom="
+                    !basesConservationConfigModel.isEnabled && {
+                      value:
+                        'To set the thresholds, first activate the colouring.',
+                      autoHide: false,
+                      pt: { text: 'text-xs text-center' }
+                    }
+                  "
+                  class="flex gap-4 rounded-md border border-zinc-300 bg-white p-2 shadow-sm"
+                >
+                  <div
+                    :class="{
+                      'text-slate-400': !basesConservationConfigModel.isEnabled
+                    }"
+                  >
+                    <label
+                      id="low-conservation-threshold-label"
+                      class="font-thin italic"
+                    >
+                      Little conserved
+                      <span
+                        v-tooltip.bottom="
+                          basesConservationConfigModel.isEnabled && {
+                            value:
+                              'The conservation rate under which to color the nucleotides with the \'little conserved\' color.',
+                            autoHide: false,
+                            pt: { text: 'text-xs text-center' }
+                          }
+                        "
+                      >
+                        <icon-fa6-regular-circle-question
+                          class="mb-0.5 ml-1 inline"
+                        />
+                      </span>
+                    </label>
+                    <Slider
+                      v-model="localBasesConservationThresholds.low"
+                      :pt="{
+                        root: {
+                          style: {
+                            backgroundColor: basesConservationColours.middle
+                          }
+                        },
+                        range: {
+                          style: {
+                            backgroundColor: basesConservationColours.low
+                          }
+                        }
+                      }"
+                      :disabled="!basesConservationConfigModel.isEnabled"
+                      class="my-2 w-full"
+                      :step="0.05"
+                      :min="0"
+                      :max="0.5"
+                      aria-labelledby="low-conservation-threshold-label"
+                      @slideend="eventHandlers.basesConservation.lowThreshold"
+                    />
+                    <div class="w-full text-center font-mono">
+                      {{
+                        Math.round(localBasesConservationThresholds.low * 100)
+                      }}%
+                    </div>
+                  </div>
+                  <div
+                    :class="{
+                      'text-slate-400': !basesConservationConfigModel.isEnabled
+                    }"
+                  >
+                    <label
+                      id="high-conservation-threshold-label"
+                      class="font-thin italic"
+                    >
+                      Highly conserved
+                      <span
+                        v-tooltip.bottom="
+                          basesConservationConfigModel.isEnabled && {
+                            value:
+                              'The conservation rate above which to color the nucleotides with the \'highly conserved\' color.',
+                            autoHide: false,
+                            pt: { text: 'text-xs text-center' }
+                          }
+                        "
+                      >
+                        <icon-fa6-regular-circle-question
+                          class="mb-0.5 ml-1 inline"
+                        />
+                      </span>
+                    </label>
+                    <Slider
+                      v-model="localBasesConservationThresholds.high"
+                      :pt="{
+                        root: {
+                          style: {
+                            backgroundColor: basesConservationColours.high
+                          }
+                        },
+                        range: {
+                          style: {
+                            backgroundColor: basesConservationColours.middle
+                          }
+                        }
+                      }"
+                      :disabled="!basesConservationConfigModel.isEnabled"
+                      class="my-2 w-full"
+                      :step="0.05"
+                      :min="0.5"
+                      :max="1"
+                      aria-labelledby="high-conservation-threshold-label"
+                      @slideend="eventHandlers.basesConservation.highThreshold"
+                    />
+                    <div class="w-full text-center font-mono">
+                      {{
+                        Math.round(localBasesConservationThresholds.high * 100)
+                      }}%
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </label>
+          </div>
+        </TabPanel>
+
+        <TabPanel
+          header="Modifications conservation"
+          :pt="{
+            headerAction: {
+              style: {
+                background: 'none'
+              }
+            }
+          }"
+        >
+          <div class="flex flex-wrap gap-8">
+            <div class="flex flex-col gap-2">
+              <label for="track-selection" class="text-sm"> Tracks </label>
+              <div class="flex grow flex-col justify-center">
+                <MultiSelect
+                  :model-value="conservationAnalysisConfigModel.trackIds"
+                  :options="conservationAnalysisTrackOptions"
+                  option-label="label"
+                  option-value="id"
+                  multiple
+                  placeholder="Select tracks..."
+                  input-id="track-selection"
+                  @update:model-value="
+                    eventHandlers.conservationAnalysis.trackIds
+                  "
+                />
+              </div>
+            </div>
+            <div class="flex flex-col gap-2">
+              <label for="object-types-selection" class="text-sm">
+                Modification type
+              </label>
+              <div class="flex grow flex-col justify-center">
+                <MultiSelect
+                  :model-value="conservationAnalysisConfigModel.objectTypes"
+                  :options="conservationAnalysisObjectTypeOptions"
+                  option-label="label"
+                  option-value="type"
+                  multiple
+                  placeholder="Select object types..."
+                  input-id="object-types-selection"
+                  @update:model-value="
+                    eventHandlers.conservationAnalysis.objectTypes
+                  "
+                >
+                  <template #option="{ option }">
+                    <BaseRenderedMarkdown
+                      :stringified-markdown="option.label"
+                      inline-content
+                    />
+                  </template>
+                  <template #value="{ value }">
+                    <BaseRenderedMarkdown
+                      v-if="value && value.length"
+                      :stringified-markdown="value.join(', ')"
+                      inline-content
+                    />
+                  </template>
+                </MultiSelect>
+              </div>
+            </div>
+
+            <div class="flex flex-col gap-2">
+              <label for="analysis-type-selection" class="text-sm">
+                Analysis type
+                <span
+                  v-tooltip.bottom="{
+                    value: `• Specific: highlights positions modified on the selected sequences only (all of them).
+
+                    • Common: highlights positions modified on the selected sequences at least (all of them).`,
+                    autoHide: false,
+                    pt: { text: 'text-xs w-[40ch]' }
+                  }"
+                >
+                  <icon-fa6-regular-circle-question
+                    class="mb-0.5 ml-1 inline"
+                  />
+                </span>
+              </label>
+              <div
+                v-tooltip.bottom="
+                  !(
+                    conservationAnalysisConfigModel.objectTypes.length &&
+                    props.conservationAnalysisConfigModel.objectTypes.length
+                  ) && {
+                    value:
+                      'First select some sequences and modification types to chose a conservation analysis type.',
+                    autoHide: false,
+                    pt: { text: 'text-xs' }
+                  }
+                "
+                class="flex grow flex-col justify-center"
+              >
+                <SelectButton
+                  :model-value="conservationAnalysisConfigModel.analysisType"
+                  :options="CONSERVATION_ANALYSIS_TYPES_OPTIONS"
+                  option-label="label"
+                  option-value="analysisType"
+                  :disabled="
+                    !(
+                      conservationAnalysisConfigModel.objectTypes.length &&
+                      props.conservationAnalysisConfigModel.objectTypes.length
+                    )
+                  "
+                  input-id="analysis-type-selection"
+                  @update:model-value="
+                    eventHandlers.conservationAnalysis.analysisType
+                  "
+                />
+              </div>
+            </div>
+          </div>
+        </TabPanel>
+      </TabView>
+    </template>
+
+    <!-- <template v-if="legendItems" #center>
+      <BaseLegendButtonOverlay button-text="Legend" :items="legendItems">
+        <template #item="{ item }">
+          <slot name="legend-item" :item="item" />
+        </template>
+        <template #item-icon="{ item }">
+          <slot name="legend-item-icon" :item="item" />
+        </template>
+        <template #item-title="{ item }">
+          <slot name="legend-item-title" :item="item" />
+        </template>
+        <template #item-description="{ item }">
+          <slot name="legend-item-description" :item="item" />
+        </template>
+      </BaseLegendButtonOverlay>
+    </template> -->
+
+    <!-- <template #end>
+      <Button
+        outlined
+        severity="secondary"
+        :class="[
+          clipboardState === ClipboardStateModel.PostCopy &&
+            '!bg-lime-100 !text-lime-700',
+          'flex min-w-[18ch] justify-center'
+        ]"
+        :loading="clipboardState === ClipboardStateModel.Busy"
+        @click="sequenceToClipboard"
+      >
+        <span
+          v-if="clipboardState === ClipboardStateModel.Busy"
+          class="mr-2 h-5 overflow-hidden text-xl"
+        >
+          <icon-fa6-solid-dna class="animate-[dnaSpin_.5s_linear_infinite]" />
+          <icon-fa6-solid-dna class="animate-[dnaSpin_.5s_linear_infinite]" />
+        </span>
+        <icon-fa6-solid-circle-check
+          v-else-if="clipboardState === ClipboardStateModel.PostCopy"
+          class="mr-2 text-xl"
+        />
+        <icon-fa6-regular-copy v-else class="mr-2 text-xl" />
+        {{
+          clipboardState === ClipboardStateModel.Busy
+            ? 'Copying...'
+            : clipboardState === ClipboardStateModel.PostCopy
+            ? 'Copied !'
+            : 'Copy sequence'
+        }}
+      </Button>
+    </template> -->
+  </Toolbar>
+</template>
diff --git a/src/components/SequenceAlignmentTrackNames.vue b/src/components/SequenceAlignmentTrackNames.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e093b10f650a7e6ac1c661d8f9c25fc2fc31ec8e
--- /dev/null
+++ b/src/components/SequenceAlignmentTrackNames.vue
@@ -0,0 +1,123 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { computed, ref, watchEffect } from 'vue'
+/**
+ * Composables imports.
+ */
+import { useElementSize } from '@vueuse/core'
+/**
+ * Types imports.
+ */
+import type { AlignmentTrackModel } from './SequenceAlignment.vue'
+
+const props = defineProps<{
+  /** The tracks of which to display the names. */
+  tracks: AlignmentTrackModel[]
+  /** The width of the track names, based on the longest name width. */
+  trackNamesWidthModel?: number
+}>()
+
+const emit = defineEmits<{
+  /** Event used to update the `v-model:trackNamesWidthModel` value. */
+  'update:trackNamesWidthModel': [trackNamesWidthModel: number]
+}>()
+
+/**
+ * Names of the tracks DOM `HTMLElement` array.
+ */
+const trackNameElements = ref<HTMLElement[]>([])
+
+/**
+ * Sizes of the names of the tracks DOM `HTMLElements`.
+ */
+const trackNameElementSizes = computed(() =>
+  trackNameElements.value.map((trackNameElement) => {
+    return useElementSize(trackNameElement)
+  })
+)
+
+/**
+ * Watcher to compute & rise the width of the track names to parent.
+ */
+watchEffect(() => {
+  emit(
+    'update:trackNamesWidthModel',
+    trackNameElementSizes.value.reduce(
+      // Get the maximum amongst the track name element's widths.
+      (maxWidth, trackNameElementSize, trackIndex) => {
+        const trackNameElementWidth =
+          trackNameElementSize.width.value +
+          (props.tracks[trackIndex]?.isReference ? 50 : 0) +
+          15
+        return trackNameElementWidth > maxWidth
+          ? trackNameElementWidth
+          : maxWidth
+      },
+      0
+    )
+  )
+})
+</script>
+
+<template>
+  <div
+    class="mt-8 inline-flex w-full flex-col whitespace-nowrap transition-transform duration-500"
+  >
+    <div
+      v-for="track in tracks"
+      :key="track.id"
+      :class="[
+        'flex min-h-[2.125rem] border-2 border-transparent italic text-slate-400',
+        {
+          'conservation-track-label justify-end': track.isInformation
+        }
+      ]"
+    >
+      <component
+        :is="track.isReference ? 'RouterLink' : 'span'"
+        ref="trackNameElements"
+        v-tooltip="{
+          value: track.name,
+          pt: {
+            root: 'ml-2',
+            text: {
+              style: { textAlign: 'center', fontWeight: '600' }
+            }
+          }
+        }"
+        :to="
+          track.isReference && {
+            name: 'targetDetails',
+            query: { id: track.id }
+          }
+        "
+        :class="{
+          'rounded-full border border-slate-400 px-2 text-center font-mono text-xl not-italic':
+            track.isInformation,
+          'font-bold underline decoration-transparent decoration-dashed transition-all duration-200 hover:decoration-inherit':
+            track.isReference
+        }"
+      >
+        {{ track.shortname || track.id }}
+      </component>
+
+      <span
+        v-if="track.isReference"
+        v-tooltip="{
+          value: 'This sequence is a reference sequence.',
+          pt: { text: 'text-xs' }
+        }"
+        class="small-caps my-auto ml-3 rounded-lg border-2 border-solid border-slate-400 bg-slate-100 px-1.5 text-sm font-bold text-slate-400"
+      >
+        Ref
+      </span>
+
+      <div
+        v-if="!track.isInformation"
+        class="track-name-arrow relative grow before:absolute before:left-2 before:right-0 before:top-1/2 before:-translate-y-[1px] before:border-t-2 after:absolute after:right-0 after:top-1/2 after:h-2 after:w-2 after:-translate-y-1/2 after:rotate-45 after:border-r-2 after:border-t-2 after:border-slate-400"
+      />
+    </div>
+  </div>
+</template>
diff --git a/src/components/SequenceBoard.vue b/src/components/SequenceBoard.vue
index 3c012016b7eebb36029ad42baf89822feb93a54a..df6849ba99e62b4483eefad43b90731968f006c8 100644
--- a/src/components/SequenceBoard.vue
+++ b/src/components/SequenceBoard.vue
@@ -16,7 +16,7 @@ import IconFa6SolidCircleCheck from '~icons/fa6-solid/circle-check'
 import IconFa6RegularCopy from '~icons/fa6-regular/copy'
 import IconFa6SolidCircleInfo from '~icons/fa6-solid/circle-info'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import {
   useElementBounding,
@@ -24,13 +24,17 @@ import {
   useMutationObserver,
   useResizeObserver
 } from '@vueuse/core'
-import { inRange as _inRange } from 'lodash-es'
+/**
+ * Other 3rd-party imports
+ */
+import { inRange as _inRange, mapValues as _mapValues } from 'lodash-es'
 /**
  * Types imports
  */
 import type { TailwindDefaultColorNameModel } from '@/typings/styleTypes'
 import type { LegendItemModel } from '@/components/BaseLegendButtonOverlay.vue'
 import type { RouteLocationRaw } from 'vue-router'
+import type { StyleValue } from 'vue'
 /**
  * Utils imports
  */
@@ -38,22 +42,22 @@ import { promisedWait } from '@/utils/promise'
 import { range } from '@/utils/numbers'
 
 /**
- * A group of nucleotides to highlight on the sequence.
+ * An object to highlight on the sequence.
  */
-export interface highlightGroupModel {
-  /** First position to highlight (starts at 1). */
+export interface objectModel {
+  /** Start position of the object (starts at 1). */
   start: number
-  /** Last position to highlight (included). */
+  /** End position of the object (included). */
   end: number
-  /** Color(s) to use to highlight the group. */
+  /** Color(s) to use to highlight the object. */
   color: TailwindDefaultColorNameModel
-  /** Group name. */
+  /** Object name. */
   name?: string
-  /** Group type. */
+  /** Object type. */
   type?: string
-  /** Link to go to when clicking on the group. */
+  /** Link to go to when clicking on the object. */
   link?: RouteLocationRaw
-  /** Wether to show a tooltip on hover on this group. */
+  /** Wether to show a tooltip on hover on this object. */
   shouldTooltip?: boolean
 }
 
@@ -77,9 +81,9 @@ const props = defineProps<{
   sequenceId: string
   /** The sequence to represent. */
   sequence: string
-  /** Groups to highlight on the sequence. */
-  highlightedGroups?: { [groupId: string]: highlightGroupModel }
-  /** The items of the legend to display for the highlighted groups. */
+  /** Objects to highlight on the sequence. */
+  objects?: { [objectId: string]: objectModel }
+  /** The items of the legend to display for the objects. */
   legendItems?: LegendItemModel[]
 }>()
 
@@ -105,12 +109,12 @@ defineSlots<{
   'legend-item-description': (props: {
     /** The item of which to customise the description. */ item: LegendItemModel
   }) => any
-  /** Custom tooltip group items template */
+  /** Custom tooltip object items template */
   'tooltip-item': (props: {
-    /** The group of the item to customise */
-    group: highlightGroupModel
-    /** The ID of the group of the item to customise */
-    groupId: string
+    /** The object of the item to customise */
+    object: objectModel
+    /** The ID of the object of the item to customise */
+    objectId: string
   }) => any
 }>()
 
@@ -161,93 +165,92 @@ const splitSequence = computed(() =>
 )
 
 /**
- * Wether a nucleotide is in a given highlighted group or not.
+ * Wether a nucleotide is in a given object or not.
  * @param position The position of the nucleotide to check.
- * @param groupId The id of the group to check for.
- * @returns `true` if position if in the given group, `false` otherwise.
+ * @param objectId The id of the object to check for.
+ * @returns `true` if position if in the given object, `false` otherwise.
  */
-const isInHighlightedGroup = (position: number, groupId: string): boolean => {
-  const highlightedGroup = props.highlightedGroups?.[groupId]
+const isInObject = (position: number, objectId: string): boolean => {
+  const object = props.objects?.[objectId]
   return (
-    !!highlightedGroup &&
-    _inRange(position, highlightedGroup.start, highlightedGroup.end + 1)
+    !!object &&
+    _inRange(position, object.start, object.end + 1)
   )
 }
 
 /**
- * Gets the IDs of the highlighted groups containing a nucleotide.
- * @param position The position of the nucleotide for which to get group IDs.
- * @returns A list of the IDs of the highlighted groups containing the nucleotide.
+ * Gets the IDs of the objects containing a nucleotide.
+ * @param position The position of the nucleotide for which to get object IDs.
+ * @returns A list of the IDs of the objects containing the nucleotide.
  */
-const highlightedGroupIdsContaining = (position: number): string[] =>
-  props.highlightedGroups
-    ? Object.keys(props.highlightedGroups).filter((groupId) =>
-        isInHighlightedGroup(position, groupId)
+const objectIdsContaining = (position: number): string[] =>
+  props.objects
+    ? Object.keys(props.objects).filter((objectId) =>
+        isInObject(position, objectId)
       )
     : []
 
 /**
- * Gets the highlighted groups containing a nucleotide.
- * @param position The position of the nucleotide for which to get group.
- * @returns A list of tuples, `[group ID, group]` for each of the highlighted
- * groups containing the nucleotide.
+ * Gets the objects containing a nucleotide.
+ * @param position The position of the nucleotide for which to get objects.
+ * @returns A list of tuples, `[object ID, object]` for each of the objects
+ * containing the nucleotide.
  */
-const highlightedGroupsContaining = (
+const objectsContaining = (
   position: number
-): [string, highlightGroupModel][] =>
-  props.highlightedGroups
-    ? Object.entries(props.highlightedGroups).filter(([groupId]) =>
-        isInHighlightedGroup(position, groupId)
+): [string, objectModel][] =>
+  props.objects
+    ? Object.entries(props.objects).filter(([objectId]) =>
+        isInObject(position, objectId)
       )
     : []
 
 /**
- * Whether a nucleotide is in any highlighted group.
+ * Whether a nucleotide is in any object.
  * @param position The position of the nucleotide to check.
- * @returns `true` if the nucleotide is in any highlighted group, `false` otherwise.
+ * @returns `true` if the nucleotide is in any object, `false` otherwise.
  */
-const isInAnyHighlightedGroup = (position: number): boolean =>
-  !!highlightedGroupIdsContaining(position).length
+const isInAnyObject = (position: number): boolean =>
+  !!objectIdsContaining(position).length
 
 /**
- * Set of all the boundary positions (start & end) of all highlighted groups on
+ * Set of all the boundary positions (start & end) of all objects on
  * the sequence.
  */
-const highlightedGroupsBoundaryPositions = computed(
+const objectsBoundaryPositions = computed(
   () =>
-    props.highlightedGroups &&
-    Object.values(props.highlightedGroups).reduce(
-      (highlightedGroupsBoundaryPositions, highlightedGroup) =>
-        highlightedGroupsBoundaryPositions
-          .add(highlightedGroup.start)
-          .add(highlightedGroup.end),
+    props.objects &&
+    Object.values(props.objects).reduce(
+      (objectsBoundaryPositions, object) =>
+        objectsBoundaryPositions
+          .add(object.start)
+          .add(object.end),
       new Set<number>()
     )
 )
 
 /**
- * Whether a nucleotide is a boundary position (start or end) of an highlighted
- * group.
+ * Whether a nucleotide is a boundary position (start or end) of an object.
  * @param position The position of the nucleotide to check.
- * @returns `true` if the nucleotide is the start of an highlighted group, `false` otherwise.
+ * @returns `true` if the nucleotide is the start of an object, `false` otherwise.
  */
-const isHighlightedGroupBoundary = (position: number): boolean =>
-  !!highlightedGroupsBoundaryPositions.value?.has(position)
+const isObjectBoundary = (position: number): boolean =>
+  !!objectsBoundaryPositions.value?.has(position)
 
 /**
  * Composes the Tailwind color name in which to paint a nucleotide based on its
  * position.
  * @param position The position for which to compose the color.
- * @returns `slate` if there is no or several boxes at the given position, the
- * Tailwind color name of the box if there is only one.
+ * @returns `slate` if there is no or several object at the given position, the
+ * Tailwind color name of the object if there is only one.
  */
-const composeHighlightedPositionColor = (
+const composeInObjectPositionColor = (
   position: number
 ): TailwindDefaultColorNameModel => {
-  const highlightedGroupIds = highlightedGroupIdsContaining(position)
-  // If only one group, use its color, otherwise, use 'slate'
-  return highlightedGroupIds.length === 1 && highlightedGroupIds[0]
-    ? props.highlightedGroups?.[highlightedGroupIds[0]]?.color || 'slate'
+  const objectIds = objectIdsContaining(position)
+  // If only one object, use its color, otherwise, use 'slate'
+  return objectIds.length === 1 && objectIds[0]
+    ? props.objects?.[objectIds[0]]?.color || 'slate'
     : 'slate'
 }
 
@@ -264,18 +267,9 @@ const sequenceContainerElement = ref<HTMLElement>()
  */
 const sequenceGroupElements = ref<HTMLElement[]>([])
 /**
- * Labels of the positions of the first nucleotide of each group DOM `HTMLElement`.
- * array
- */
-const groupsPositionsElements = ref<HTMLElement[]>([])
-/**
- * First & last nucleotides of each box DOM `HTMLElement` array.
+ * First & last nucleotides of each object DOM `HTMLElement` array.
  */
-const boxBoundaryElements = ref<HTMLElement[]>([])
-/**
- * Boxes DOM `HTMLElement` array.
- */
-const boxElements = ref<HTMLElement[]>([])
+const objectBoundaryElements = ref<HTMLElement[]>([])
 
 /**
  * Last split sequence group DOM `HTMLElement`.
@@ -342,44 +336,52 @@ const lineHeight = computed(
 )
 
 /**
- * Dictionary of the number of line on which each highlighted group spreads,
- * by group ID.
+ * Dictionary of the number of line on which each object spreads, by object ID.
  */
-const highlightedGroupsLineCount = ref<{ [groupId: string]: number }>()
+const objectsLineCount = ref<{
+  [objectId: string]: number | undefined
+}>()
 
 /**
- * Updates the number of line on which each highlighted group spreads.
- * @returns The updated number of line on which each highlighted group spreads.
+ * Updates the number of line on which each object spreads.
+ * @returns The updated number of line on which each object spreads.
  * @description Retrieves the line count by getting the difference between the
- * top of the last nucleotide of the box and the top of the first one, and
+ * top of the last nucleotide of the object and the top of the first one, and
  * dividing by the line height.
  */
-const updateHighlightedGroupsLineCount =
-  (): typeof highlightedGroupsLineCount.value =>
-    (highlightedGroupsLineCount.value =
-      props.highlightedGroups &&
-      Object.entries(props.highlightedGroups).reduce(
-        (highlightedGroupsLineCount, [groupId, group]) => ({
-          ...highlightedGroupsLineCount,
-          [groupId]:
-            lineHeight.value &&
-            Math.round(
-              ((
-                boxBoundaryElements.value.find(
-                  (element) => element.dataset.position === group.end.toString()
-                )?.offsetParent as HTMLElement
-              )?.offsetTop -
-                (
-                  boxBoundaryElements.value.find(
-                    (element) =>
-                      element.dataset.position === group.start.toString()
-                  )?.offsetParent as HTMLElement
-                )?.offsetTop) /
-                lineHeight.value
-            ) + 1
-        }),
-        {}
-      ))
+const updateObjectsLineCount = () =>
+  (objectsLineCount.value = _mapValues(
+    props.objects,
+    (object) => {
+      // Parent DOM elements of the first and last nucleotide of the object
+      const objectStartNucleotideElementParent = objectBoundaryElements.value.find(
+        (element) =>
+          element.dataset.position === object.start.toString()
+      )?.offsetParent
+      const objectEndNucleotideElementParent = objectBoundaryElements.value.find(
+        (element) =>
+          element.dataset.position === object.end.toString()
+      )?.offsetParent
+
+      if (
+        !(
+          objectStartNucleotideElementParent instanceof HTMLElement &&
+          objectEndNucleotideElementParent instanceof HTMLElement
+        )
+      ) {
+        return undefined
+      }
+
+      return (
+        lineHeight.value &&
+        Math.round(
+          (objectEndNucleotideElementParent.offsetTop -
+            objectStartNucleotideElementParent.offsetTop) /
+            lineHeight.value
+        ) + 1
+      )
+    }
+  ))
 
 /**
  * Width of the sequence container.
@@ -426,120 +428,17 @@ const updateSequenceContainerContentWidth =
   }
 
 /**
- * Updates all the DOM positions & sizes.
+ * Updates all non-reactive values.
  */
 const update = (): void => {
-  updateHighlightedGroupsLineCount()
+  updateObjectsLineCount()
   updateSequenceContainerContentWidth()
 }
 
 /**
- * Redraws the nucleotide positions of the start of each split sequence groups.
- */
-const redrawGroupNumbers = (): void => {
-  groupsPositionsElements.value.forEach((groupNumberElement) => {
-    const matchingSequenceGroupElement = sequenceGroupElements.value.find(
-      (element) => {
-        return (
-          element.dataset.groupIndex === groupNumberElement.dataset.groupIndex
-        )
-      }
-    )
-
-    groupNumberElement.style.left = `${
-      matchingSequenceGroupElement?.offsetLeft || 0
-    }px`
-    groupNumberElement.style.top = `calc(${
-      matchingSequenceGroupElement?.offsetTop || 0
-    }px - 1.25rem)`
-  })
-}
-
-/**
- * Redraws the boxes of highlighted groups.
- */
-const redrawBoxes = (): void => {
-  boxElements.value.forEach((boxElement) => {
-    const matchingBoxFirstNucleotideElement = boxBoundaryElements.value.find(
-      (element) => element.dataset.position === boxElement.dataset.start
-    )
-    const matchingBoxLastNucleotideElement = boxBoundaryElements.value.find(
-      (element) => element.dataset.position === boxElement.dataset.end
-    )
-
-    if (
-      !matchingBoxFirstNucleotideElement?.offsetParent ||
-      !matchingBoxLastNucleotideElement?.offsetParent
-    ) {
-      return
-    }
-
-    const matchingBoxFirstNucleotideElementTop =
-      (matchingBoxFirstNucleotideElement?.offsetParent as HTMLElement)
-        .offsetTop + (matchingBoxFirstNucleotideElement?.offsetTop || 0)
-    const matchingBoxFirstNucleotideElementLeft =
-      (matchingBoxFirstNucleotideElement?.offsetParent as HTMLElement)
-        .offsetLeft + (matchingBoxFirstNucleotideElement?.offsetLeft || 0)
-    const matchingBoxLastNucleotideElementLeft =
-      (matchingBoxLastNucleotideElement?.offsetParent as HTMLElement)
-        .offsetLeft + (matchingBoxLastNucleotideElement?.offsetLeft || 0)
-    const matchingBoxLastNucleotideElementRight =
-      matchingBoxLastNucleotideElementLeft +
-      (matchingBoxLastNucleotideElement?.offsetWidth || 0)
-
-    Array.from(boxElement.children as HTMLCollectionOf<HTMLElement>).forEach(
-      (boxFragmentElement, boxFragmentIndex) => {
-        boxFragmentElement.style.top = `${
-          matchingBoxFirstNucleotideElementTop +
-          boxFragmentIndex * (lineHeight.value || 0)
-        }px`
-
-        const boxFragmentElementLeft =
-          boxFragmentIndex === 0 ? matchingBoxFirstNucleotideElementLeft : 0
-
-        boxFragmentElement.style.left =
-          boxFragmentIndex === 0
-            ? `calc(${boxFragmentElementLeft}px - 0.125rem)`
-            : '0'
-
-        boxFragmentElement.style.width = `calc(${
-          boxFragmentIndex === boxElement.children.length - 1
-            ? boxFragmentIndex === 0
-              ? `${
-                  matchingBoxLastNucleotideElementRight -
-                  matchingBoxFirstNucleotideElementLeft
-                }px`
-              : `${matchingBoxLastNucleotideElementRight}px`
-            : `${
-                (sequenceContainerContentWidth.value || 0) -
-                boxFragmentElementLeft
-              }px`
-        } + 0.25rem)`
-      }
-    )
-  })
-}
-
-/**
- * Redraws every absolutely positioned objects.
- */
-const redraw = (): void => {
-  redrawGroupNumbers()
-  redrawBoxes()
-}
-
-/**
- * Updates values then redraws every absolutely positioned objects.
- */
-const updateAndRedraw = (): void => {
-  update()
-  redraw()
-}
-
-/**
- * Exposes methods to manually trigger update & redraw of boxes.
+ * Exposes methods to manually trigger updates.
  */
-defineExpose({ update, redraw, updateAndRedraw })
+defineExpose({ update })
 
 /**
  * Whether the sequence is visible or not.
@@ -549,49 +448,156 @@ const isSequenceContainerElementVisible = useElementVisibility(
 )
 
 /**
- * Sets hook to update and (re)draw on component mount.
+ * Sets hook to update on component mount.
  */
-onMounted(updateAndRedraw)
+onMounted(update)
 
 /**
- * Sets an observer to update and redraw on container resize.
+ * Sets an observer to update on container resize.
  */
 useResizeObserver(sequenceContainerElement, () => {
-  updateAndRedraw()
+  update()
   setTimeout(() => {
-    updateAndRedraw()
+    update()
   }, 100)
 })
 
 /**
- * Sets a watcher to update and redraw when resuming sequence visibility.
+ * Sets a watcher to update when resuming sequence visibility.
  */
 watch(
   [isSequenceContainerElementVisible, () => props.sequenceId],
   ([isSequenceContainerElementVisible, newSequenceId], [, oldSequenceId]) => {
     if (isSequenceContainerElementVisible || newSequenceId !== oldSequenceId) {
       setTimeout(() => {
-        updateAndRedraw()
+        update()
       }, 100)
     }
   }
 )
 
 /**
- * The highlighted boxes currently being hovered.
+ * Bounding box of sequence container DOM `HTMLElement`.
  */
-const hoveredHighlightedGroups = ref(new Set<[string, highlightGroupModel]>())
+const sequenceContainerElementBounding = useElementBounding(
+  sequenceContainerElement
+)
 
 /**
- * The highlighted boxes currently being hovered.
+ * For each sequence group first position label, the bounding box of its
+ * reference sequence group DOM element.
  */
-const lockedTooltipHighlightedGroups = ref<Set<[string, highlightGroupModel]>>()
+const groupNumberReferenceSequenceGroupElementsBounding = computed(() =>
+  Array.from({ length: nucleotideGroupsCount.value }, (_, groupNumberIndex) =>
+    useElementBounding(
+      sequenceGroupElements.value.find(
+        (sequenceGroupElement) =>
+          sequenceGroupElement.dataset.groupIndex ===
+          groupNumberIndex.toString()
+      )
+    )
+  )
+)
+
+/**
+ * The style to apply to the sequence group first position label DOM element.
+ */
+const groupNumberStyles = computed(() =>
+  groupNumberReferenceSequenceGroupElementsBounding.value.map<StyleValue>(
+    (groupNumberReferenceSequenceGroupElementBounding) => ({
+      left: `${
+        groupNumberReferenceSequenceGroupElementBounding.left.value -
+        sequenceContainerElementBounding.left.value
+      }px`,
+      top: `calc(${
+        groupNumberReferenceSequenceGroupElementBounding.top.value -
+        sequenceContainerElementBounding.top.value
+      }px - 1.25rem)`
+    })
+  )
+)
+
+/**
+ * The style to apply to each fragment of each of the object boxes.
+ */
+const objectBoxStyles = computed(() =>
+  // Map objects to the styles of each of their fragment
+  _mapValues(props.objects, (object, objectId) => {
+    // DOM element of the first and last nucleotides of the object
+    const objectStartNucleotideElement = objectBoundaryElements.value.find(
+      (element) =>
+        element.dataset.position === object.start.toString()
+    )
+    const objectEndNucleotideElement = objectBoundaryElements.value.find(
+      (element) => element.dataset.position === object.end.toString()
+    )
+
+    if (
+      !(
+        objectStartNucleotideElement?.offsetParent instanceof HTMLElement &&
+        objectEndNucleotideElement?.offsetParent instanceof HTMLElement
+      )
+    ) {
+      return
+    }
+
+    // Absolute positions of the DOM elements of the first and last nucleotide
+    // of the object
+    const objectStartNucleotideElementTop =
+      objectStartNucleotideElement.offsetParent.offsetTop +
+      (objectStartNucleotideElement?.offsetTop || 0)
+    const objectStartNucleotideElementLeft =
+      objectStartNucleotideElement.offsetParent.offsetLeft +
+      (objectStartNucleotideElement?.offsetLeft || 0)
+    const objectEndNucleotideElementLeft =
+      objectEndNucleotideElement.offsetParent.offsetLeft +
+      (objectEndNucleotideElement.offsetLeft || 0)
+    const objectEndNucleotideElementRight =
+      objectEndNucleotideElementLeft +
+      (objectEndNucleotideElement.offsetWidth || 0)
+
+    // Number of fragment in which the current object box is divided
+    const objectBoxFragmentsCount =
+      objectsLineCount.value?.[objectId] || 0
+
+    // Array of length equals # of fragments, containing style for each of them
+    return Array.from(
+      { length: objectBoxFragmentsCount },
+      (_, fragmentIndex): StyleValue => ({
+        top: `${
+          objectStartNucleotideElementTop +
+          fragmentIndex * (lineHeight.value || 0)
+        }px`,
+        left:
+          fragmentIndex === 0
+            ? `calc(${objectStartNucleotideElementLeft}px - 0.125rem)`
+            : '0',
+        right: `calc(${
+          (sequenceContainerElementBounding.width.value || 0) -
+          (fragmentIndex === objectBoxFragmentsCount - 1
+            ? objectEndNucleotideElementRight
+            : sequenceContainerContentWidth.value || 0)
+        }px - 0.125rem)`
+      })
+    )
+  })
+)
+
+/**
+ * The objects currently being hovered.
+ */
+const hoveredObjects = ref(new Set<[string, objectModel]>())
+
+/**
+ * The objects currently being hovered.
+ */
+const lockedTooltipObjects = ref<Set<[string, objectModel]>>()
 
 /**
  * DOM elements of objects to display in the tooltip.
  */
-const tooltipHighlightedGroups = computed(
-  () => lockedTooltipHighlightedGroups.value || hoveredHighlightedGroups.value
+const tooltipObjects = computed(
+  () => lockedTooltipObjects.value || hoveredObjects.value
 )
 
 /**
@@ -603,7 +609,7 @@ const tooltipComponent = ref<InstanceType<typeof BaseLockableTooltip>>()
  * Locks the tooltip and the values to display in it.
  */
 const lockTooltip = () => {
-  lockedTooltipHighlightedGroups.value = new Set(hoveredHighlightedGroups.value)
+  lockedTooltipObjects.value = new Set(hoveredObjects.value)
   tooltipComponent.value?.lockTooltipIfUnlocked()
 }
 </script>
@@ -617,7 +623,7 @@ const lockTooltip = () => {
           v-model="nucleotideGroupsSize"
           :options="[5, 10, 20, 50, 100]"
           class="mt-2 w-52"
-          @hide="updateAndRedraw"
+          @hide="update"
         >
           <template #option="{ option }">{{ option }} nucleotides</template>
           <template #value="{ value }">{{ value }} nucleotides</template>
@@ -711,59 +717,57 @@ const lockTooltip = () => {
         >
           <span
             v-if="
-              isHighlightedGroupBoundary(
+              isObjectBoundary(
                 nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
               )
             "
-            ref="boxBoundaryElements"
+            ref="objectBoundaryElements"
             :data-position="
               nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
             "
             :class="[
               'relative mx-[.0625rem] border-2 border-transparent px-0.5 pt-0.5',
-              isInAnyHighlightedGroup(
-                nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
-              ) && [
-                `text-${composeHighlightedPositionColor(
+              [
+                `text-${composeInObjectPositionColor(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 )}-600`,
-                'modification font-semibold'
+                'font-semibold'
               ]
             ]"
           >
             <span
               v-if="
-                highlightedGroupsContaining(
+                objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 ).find(
-                  ([_highlightedGroupId, highlightedGroup]) =>
-                    highlightedGroup.shouldTooltip
+                  ([, object]) =>
+                    object.shouldTooltip
                 )
               "
               :class="[
                 'absolute -bottom-0.5 -left-[0.1875rem] -right-[0.1875rem] -top-0.5',
-                highlightedGroupsContaining(
+                objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 ).find(
-                  ([_highlightedGroupId, highlightedGroup]) =>
-                    highlightedGroup.link
+                  ([, object]) =>
+                    object.link
                 )
                   ? 'cursor-pointer'
                   : 'cursor-help'
               ]"
               @mouseenter="
-                highlightedGroupsContaining(
+                objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 ).forEach(
-                  ([highlightedGroupId, highlightedGroup]) =>
-                    highlightedGroup.shouldTooltip &&
-                    hoveredHighlightedGroups.add([
-                      highlightedGroupId,
-                      highlightedGroup
+                  ([objectId, object]) =>
+                    object.shouldTooltip &&
+                    hoveredObjects.add([
+                      objectId,
+                      object
                     ])
                 )
               "
-              @mouseleave="hoveredHighlightedGroups.clear()"
+              @mouseleave="hoveredObjects.clear()"
               @click="lockTooltip"
             />{{ nucleotide }}
           </span>
@@ -771,49 +775,49 @@ const lockTooltip = () => {
             v-else
             :class="[
               'relative mx-[.0625rem] border-2 border-transparent px-0.5 pt-0.5',
-              isInAnyHighlightedGroup(
+              isInAnyObject(
                 nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
               ) && [
-                `text-${composeHighlightedPositionColor(
+                `text-${composeInObjectPositionColor(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 )}-600`,
-                'modification font-semibold'
+                'font-semibold'
               ]
             ]"
           >
             <span
               v-if="
-                highlightedGroupsContaining(
+                objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 ).find(
-                  ([_highlightedGroupId, highlightedGroup]) =>
-                    highlightedGroup.shouldTooltip
+                  ([, object]) =>
+                    object.shouldTooltip
                 )
               "
               :class="[
                 'absolute -bottom-0.5 -left-[0.1875rem] -right-[0.1875rem] -top-0.5',
-                highlightedGroupsContaining(
+                objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 ).find(
-                  ([_highlightedGroupId, highlightedGroup]) =>
-                    highlightedGroup.link
+                  ([, object]) =>
+                    object.link
                 )
                   ? 'cursor-pointer'
                   : 'cursor-help'
               ]"
               @mouseenter="
-                highlightedGroupsContaining(
+                objectsContaining(
                   nucleotideIndex + groupIndex * nucleotideGroupsSize + 1
                 ).forEach(
-                  ([highlightedGroupId, highlightedGroup]) =>
-                    highlightedGroup.shouldTooltip &&
-                    hoveredHighlightedGroups.add([
-                      highlightedGroupId,
-                      highlightedGroup
+                  ([objectId, object]) =>
+                    object.shouldTooltip &&
+                    hoveredObjects.add([
+                      objectId,
+                      object
                     ])
                 )
               "
-              @mouseleave="hoveredHighlightedGroups.clear()"
+              @mouseleave="hoveredObjects.clear()"
               @click="lockTooltip"
             />{{ nucleotide }}
           </span>
@@ -823,86 +827,83 @@ const lockTooltip = () => {
       <span
         v-for="(_sequenceGroup, groupIndex) in splitSequence"
         :key="groupIndex"
-        ref="groupsPositionsElements"
         class="absolute select-none text-sm text-slate-400"
-        :data-group-index="groupIndex"
+        :style="groupNumberStyles[groupIndex]"
       >
         {{ groupIndex * nucleotideGroupsSize + 1 }}
       </span>
 
       <span
-        v-for="[highlightedGroupId, highlightedGroup] in Object.entries(
-          highlightedGroups || {}
+        v-for="[objectId, object] in Object.entries(
+          objects || {}
         )"
-        :key="highlightedGroupId"
-        ref="boxElements"
-        :data-start="highlightedGroup.start"
-        :data-end="highlightedGroup.end"
-        class="highlight-group"
+        :key="objectId"
+        class="object"
       >
         <span
-          v-for="highlightedGroupLine in range(
-            highlightedGroupsLineCount?.[highlightedGroupId] || 0
+          v-for="fragmentIndex in range(
+            objectsLineCount?.[objectId] || 0
           )"
-          :key="highlightedGroupLine"
+          :key="fragmentIndex"
+          :style="objectBoxStyles?.[objectId]?.[fragmentIndex]"
           :class="[
-            'highlight-group-fragment absolute h-8 border-y-2 bg-opacity-50 px-0.5 text-2xl mix-blend-multiply',
+            'object-fragment absolute h-8 border-y-2 bg-opacity-50 px-0.5 text-2xl mix-blend-multiply',
             [
-              `!border-${highlightedGroup.color}-600`,
-              `bg-${highlightedGroup.color}-100`
+              `!border-${object.color}-600`,
+              `bg-${object.color}-100`
             ],
             {
-              'rounded-l-xl border-l-2': highlightedGroupLine === 0,
+              'rounded-l-xl border-l-2': fragmentIndex === 0,
               'rounded-r-xl border-r-2':
-                highlightedGroupsLineCount &&
-                highlightedGroupLine + 1 ===
-                  highlightedGroupsLineCount[highlightedGroupId]
+                objectsLineCount &&
+                fragmentIndex + 1 ===
+                  objectsLineCount[objectId]
             },
-            highlightedGroup.shouldTooltip &&
-              (highlightedGroup.link ? 'cursor-pointer' : 'cursor-help')
+            object.shouldTooltip &&
+              (object.link ? 'cursor-pointer' : 'cursor-help')
           ]"
         />
       </span>
 
       <BaseLockableTooltip
         ref="tooltipComponent"
-        :show="!!hoveredHighlightedGroups.size"
+        :show="!!hoveredObjects.size"
         class="z-20 max-w-min font-sans text-base shadow-xl"
-        @unlock="lockedTooltipHighlightedGroups = undefined"
+        @unlock="lockedTooltipObjects = undefined"
       >
         <ul class="flex flex-col gap-1">
           <li
-            v-for="(highlightedGroup, index) in tooltipHighlightedGroups"
+            v-for="(object, index) in tooltipObjects"
             :key="index"
           >
             <RouterLink
-              v-if="highlightedGroup[1].link"
-              :to="highlightedGroup[1].link"
+              v-if="object[1].link"
+              :to="object[1].link"
               :class="[
-                `text-${highlightedGroup[1].color}-600`,
+                `text-${object[1].color}-600`,
                 'whitespace-nowrap'
               ]"
             >
               <slot
                 name="tooltip-item"
-                :group="highlightedGroup[1]"
-                :group-id="highlightedGroup[0]"
+                :object="object[1]"
+                :object-id="object[0]"
               >
-                {{ highlightedGroup[1].name || highlightedGroup[1].link }}
+                {{ object[1].name || object[1].link }}
                 {{
-                  highlightedGroup[1].type && ` - ${highlightedGroup[1].type}`
+                  object[1].type && ` - ${object[1].type}`
                 }}
               </slot>
             </RouterLink>
             <span v-else>
               <slot
                 name="tooltip-item"
-                :group="highlightedGroup[1]"
-                :group-id="highlightedGroup[0]"
+                :object="object[1]"
+                :object-id="object[0]"
               >
-                {{ highlightedGroup[1].name || highlightedGroup[1].link }}
+                {{ object[1].name || object[1].link }}
                 {{
-                  highlightedGroup[1].type && ` - ${highlightedGroup[1].type}`
+                  object[1].type && ` - ${object[1].type}`
                 }}
               </slot>
             </span>
@@ -917,10 +918,10 @@ const lockTooltip = () => {
 </template>
 
 <style lang="scss">
-// .sequence-parent:has(.highlight-group:hover) {
+// .sequence-parent:has(.object:hover) {
 //   // color: var(--gray-300);
 //
-//   .highlight-group-fragment {
+//   .object-fragment {
 //     border-color: var(--gray-300);
 //     background-color: var(--gray-100);
 //   }
diff --git a/src/composables/useConservationAnalysis.ts b/src/composables/useConservationAnalysis.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9d64a7f38dbfdecbf097f7a004bfd5dc2febc59a
--- /dev/null
+++ b/src/composables/useConservationAnalysis.ts
@@ -0,0 +1,226 @@
+/**
+ * Vue imports
+ */
+import { computed, toRef, type MaybeRef, type ComputedRef } from 'vue'
+/**
+ * Other 3rd-party imports
+ */
+import { groupBy as _groupBy, pick as _pick } from 'lodash-es'
+/**
+ * Types imports
+ */
+import type {
+  AlignmentObjectWithTrackIdModel,
+  AlignmentTrackModel
+} from '@/components/SequenceAlignment.vue'
+/**
+ * Utils imports
+ */
+import { isDefined, isNotEmpty } from '@/typings/typeUtils'
+
+/**
+ * A conservation analysis type.
+ */
+export enum ConservationAnalysisTypesEnum {
+  /**
+   * Visualise modifications present **only** on **all** the selected
+   * sequences
+   */
+  Specific = 0,
+  /**
+   * Visualise modifications present **at least** on **all** the selected
+   * sequences
+   */
+  Common
+}
+
+/**
+ * Configuration for the conservation analysis.
+ */
+export interface ConservationAnalysisConfigModel {
+  /** The IDs of the tracks selected for conservation analysis. */
+  trackIds: string[]
+  /** The object types selected for conservation analysis. */
+  objectTypes: string[]
+  /** The type of conservation analysis to perform
+   * See {@link ConservationAnalysisTypesEnum} for the description of each mode. */
+  analysisType: ConservationAnalysisTypesEnum | null
+}
+
+/**
+ * Reactive conservation analysis between sequences (mainly track)
+ * @param tracks The tracks of the alignment on which to perform the
+ * conservation analysis (contains selected AND unselected tracks, to be able to
+ * perform the *Specific* analysis)
+ * @param selectedAnalysisType
+ */
+export const useConservationAnalysis = (
+  tracks: MaybeRef<AlignmentTrackModel[]>,
+  config: MaybeRef<ConservationAnalysisConfigModel | null>
+): {
+  /** The track representing the conservation analysis in the alignment. */
+  track: ComputedRef<AlignmentTrackModel>
+} => {
+  /**
+   * All the modifications present on the reference track sequences.
+   */
+  const referenceTrackModifications = computed<
+    AlignmentObjectWithTrackIdModel[]
+  >(() =>
+    toRef(tracks)
+      .value.filter((track) => track.isReference)
+      .map(
+        (track) =>
+          track.objects &&
+          Object.values(track.objects).map((object) => ({
+            ...object,
+            trackId: track.id
+          }))
+      )
+      .flat()
+      .filter(isDefined)
+  )
+
+  /**
+   * Modifications present on selected track sequences.
+   */
+  const selectedModifications = computed(() =>
+    referenceTrackModifications.value.filter((modification) =>
+      toRef(config).value?.trackIds.includes(modification.trackId)
+    )
+  )
+
+  /**
+   * Modifications present on selected track sequences, filtered according to the
+   * currently selected mode (`selectedConservationAnalysisType`) & modification
+   * type(`selectedConservationAnalysisObjectTypes`).
+   *
+   * See {@link ConservationAnalysisTypesEnum} for the description of each mode.
+   */
+  const filteredSelectedModifications = computed(() => {
+    if (toRef(config).value?.analysisType == null) {
+      return []
+    }
+    return (
+      // Group modifications by position & type
+      Object.values(
+        _groupBy(
+          selectedModifications.value,
+          (selectedModification) =>
+            `${selectedModification.start}-${selectedModification.end}:${selectedModification.type}`
+        )
+      )
+        // Keep only modifications when present on every track selected for
+        // analysis (i.e. the number of modifications on a position is the same
+        // as the number of selected tracks)
+        .filter(isNotEmpty)
+        .filter(
+          (selectedModificationsByPosition) =>
+            selectedModificationsByPosition.length ===
+            toRef(config).value?.trackIds.length
+        )
+        // Keep only the modification informations common to all selected tracks
+        // for each modification (reduce modification arrays to a single one for
+        // each)
+        .map((selectedModificationsByPosition) => {
+          return _pick<
+            (typeof selectedModificationsByPosition)[0],
+            'start' | 'end' | 'color' | 'type' | 'trackId'
+          >(selectedModificationsByPosition[0], [
+            'start',
+            'end',
+            'color',
+            'type',
+            'trackId'
+          ])
+        })
+        // Keep only modifications of the selected types
+        .filter(
+          (selectedModification) =>
+            selectedModification.type &&
+            toRef(config).value?.objectTypes.includes(selectedModification.type)
+        )
+        // If in "specific" analysis mode, keep only modification if absent on
+        // every non-selected track (i.e. there is no modification with same
+        // positions on a non-selected track)
+        .filter((selectedModification) =>
+          toRef(config).value?.analysisType ===
+          ConservationAnalysisTypesEnum.Specific
+            ? !toRef(referenceTrackModifications).value.find(
+                (referenceTrackModification) =>
+                  // Using a cross-organism ID here would avoid matching 2 different
+                  // modifications taking place at the same position
+                  referenceTrackModification.start ===
+                    selectedModification?.start &&
+                  referenceTrackModification.end ===
+                    selectedModification?.end &&
+                  !toRef(config).value?.trackIds.includes(
+                    referenceTrackModification.trackId
+                  )
+              )
+            : selectedModification
+        )
+    )
+  })
+
+  /**
+   * Selected tracks for conservation analysis.
+   */
+  const selectedTracks = computed<AlignmentTrackModel[]>(
+    () =>
+      toRef(config)
+        .value?.trackIds.map((selectedTrackId) =>
+          toRef(tracks).value.find((track) => track.id === selectedTrackId)
+        )
+        .filter(isDefined) || []
+  )
+
+  /**
+   * If a conservation analysis is selected, the track to display to represent the
+   * analysis.
+   */
+  const conservationAnalysisTrack = computed<AlignmentTrackModel>(() => {
+    const objects: {
+      [objectId: string]: (typeof filteredSelectedModifications.value)[number]
+    } = {}
+
+    const sequence = Array.from(
+      {
+        length: selectedTracks.value?.[0]?.sequence.length || 0
+      },
+      (_, index) => {
+        const matchingModification = filteredSelectedModifications.value.find(
+          (modification) => modification?.start === index + 1
+        )
+
+        // No conserved modification at current position
+        if (!matchingModification) {
+          return '-'
+        }
+
+        // Add modification to object list of conservation analysis track
+        objects[`CONS_OBJ_${index}`] = {
+          ...matchingModification,
+          trackId: 'CONSERVATION_TRACK'
+        }
+
+        const modificationNucleotide = toRef(tracks).value.find(
+          (track) => track.id === matchingModification.trackId
+        )?.sequence[index]
+
+        return modificationNucleotide || '↯'
+      }
+    ).join('')
+
+    return {
+      id: 'CONSERVATION_TRACK',
+      name: 'Conservation analysis',
+      shortname: 'Conservation',
+      sequence,
+      isInformation: true,
+      objects
+    }
+  })
+
+  return { track: conservationAnalysisTrack }
+}
diff --git a/src/gql/codegen/gql.ts b/src/gql/codegen/gql.ts
index 1cdd8fd0b5c5297451891af1c63484e3dfa739b3..6e7d7be3ef22375a79e768db653a8cd7c8a8bc56 100644
--- a/src/gql/codegen/gql.ts
+++ b/src/gql/codegen/gql.ts
@@ -22,6 +22,8 @@ const documents = {
     "\n  query guideByIdQuery($id: ID) {\n    guides(where: { id: $id }) {\n      id\n      name\n      altnames\n      description\n      length\n      class\n      subclass_label\n      chromosomeConnection: parentConnection(\n        where: { node: { graphql_type: Chromosome } }\n      ) {\n        edges {\n          properties {\n            start\n            end\n            strand\n          }\n          node {\n            id\n            name\n            length\n            graphql_type\n          }\n        }\n      }\n      host_genes\n      seq\n      genome {\n        organism {\n          id\n          label\n        }\n      }\n      boxConnections: featuresConnection(\n        where: { NOT: { node: { class: DuplexFragment } } }\n      ) {\n        edges {\n          properties {\n            ... on HasFeature {\n              start\n              end\n            }\n          }\n          node {\n            id\n            annotation\n          }\n        }\n      }\n      modifications(options: { sort: [{ position: ASC }] }) {\n        id\n        name\n        type\n      }\n      modificationsAggregate {\n        count\n      }\n      interactions {\n        duplexes {\n          primaryStrandsConnection: strandsConnection(\n            where: { edge: { primary: true } }\n          ) {\n            edges {\n              properties {\n                start\n                end\n                primary\n              }\n              node {\n                seq\n                parentConnection {\n                  edges {\n                    properties {\n                      start\n                      end\n                    }\n                  }\n                }\n              }\n            }\n          }\n          secondaryStrandsConnection: strandsConnection(\n            where: { edge: { primary: false } }\n          ) {\n            edges {\n              properties {\n                start\n                end\n                primary\n              }\n              node {\n                seq\n                parentConnection {\n                  edges {\n                    properties {\n                      start\n                      end\n                    }\n                  }\n                }\n              }\n            }\n          }\n          index\n        }\n        modification {\n          id\n          name\n          position\n          symbol\n          symbol_label\n          type\n          type_short_label\n        }\n        target {\n          id\n          name\n          class\n          unit\n        }\n      }\n      cluster {\n        id\n      }\n      clusterAggregate {\n        count\n      }\n      isoform {\n        guides {\n          id\n          name\n        }\n        guidesAggregate {\n          count\n        }\n      }\n      isoformAggregate {\n        count\n      }\n      chebi_id\n      so_id\n    }\n\n    targets(\n      where: { modifications_SOME: { guides_SOME: { id: $id } } }\n      options: { sort: [{ name: ASC }] }\n    ) {\n      id\n      name\n      class\n      unit\n    }\n  }\n": types.GuideByIdQueryDocument,
     "\n  query targetByIdQuery($id: ID) {\n    targets(where: { id: $id }) {\n      id\n      name\n      altnames\n      description\n      length\n      class\n      unit\n      chromosomeConnection: parentConnection(\n        where: { node: { graphql_type: Chromosome } }\n      ) {\n        edges {\n          properties {\n            start\n            end\n            strand\n          }\n          node {\n            name\n            graphql_type\n          }\n        }\n      }\n      seq\n      genome {\n        organism {\n          id\n          label\n        }\n      }\n      modifications(options: { sort: [{ position: ASC }] }) {\n        id\n        name\n        position\n        type\n        symbol\n      }\n      modificationsAggregate {\n        count\n      }\n      interactions {\n        duplexes {\n          primaryStrandsConnection: strandsConnection(\n            where: { edge: { primary: true } }\n          ) {\n            edges {\n              properties {\n                start\n                end\n                primary\n              }\n              node {\n                seq\n                parentConnection {\n                  edges {\n                    properties {\n                      start\n                      end\n                    }\n                  }\n                }\n              }\n            }\n          }\n          secondaryStrandsConnection: strandsConnection(\n            where: { edge: { primary: false } }\n          ) {\n            edges {\n              properties {\n                start\n                end\n                primary\n              }\n              node {\n                seq\n                parentConnection {\n                  edges {\n                    properties {\n                      start\n                      end\n                    }\n                  }\n                }\n              }\n            }\n          }\n          index\n        }\n        modification {\n          id\n          name\n          position\n          symbol\n          symbol_label\n          type\n          type_short_label\n        }\n        guide {\n          id\n          name\n          subclass_label\n          class\n        }\n      }\n      chebi_id\n      so_id\n      url\n      secondary_struct_file\n    }\n\n    guides(\n      where: { modifications_SOME: { target: { id: $id } } }\n      options: { sort: [{ id: ASC }] }\n    ) {\n      id\n      name\n      class\n      chromosome: parent(where: { graphql_type: Chromosome }) {\n        name\n      }\n    }\n  }\n": types.TargetByIdQueryDocument,
     "\n  query clusterByIdQuery($id: ID) {\n    clusters(where: { id: $id }) {\n      id\n      guides(options: { sort: [{ id: ASC }] }) {\n        id\n        name\n        class\n        subclass_label\n        modificationsAggregate {\n          count\n        }\n        chromosomeConnection: parentConnection(\n          where: { node: { graphql_type: Chromosome } }\n        ) {\n          edges {\n            properties {\n              start\n              end\n            }\n          }\n        }\n      }\n      guidesAggregate {\n        count\n      }\n      referenceGuide: guides(options: { limit: 1 }) {\n        chromosome: parent(where: { graphql_type: Chromosome }) {\n          id\n          name\n        }\n        genome {\n          organism {\n            label\n            id\n          }\n        }\n      }\n    }\n  }\n": types.ClusterByIdQueryDocument,
+    "\n  query targetAlignmentQuery($targetName: String, $organismIds: [Int!]) {\n    targetBase: targets {\n      name\n      unit\n      genome {\n        organism {\n          id\n          label\n        }\n      }\n    }\n\n    organismsBase: organisms {\n      label\n      id\n    }\n\n    organisms(\n      where: {\n        tableEntries_SOME: { modification: { target: { name: $targetName } } }\n      }\n    ) {\n      id\n    }\n\n    selectableTargets: targets(\n      where: {\n        name: $targetName\n        genome: { organism: { id_IN: $organismIds } }\n      }\n    ) {\n      id\n      genome {\n        organism {\n          shortlabel\n        }\n      }\n    }\n  }\n": types.TargetAlignmentQueryDocument,
+    "\n  query guideAlignmentQuery(\n    $guideSubclasses: [GuideClass!]\n    $guideName: String\n    $organismIds: [Int!]\n  ) {\n    guideBase: guides {\n      name\n      subclass\n      subclass_label\n      genome {\n        organism {\n          id\n        }\n      }\n    }\n\n    guideNamesFilteredBySubclass: guides(\n      where: { subclass_IN: $guideSubclasses }\n    ) {\n      name\n      genome {\n        organism {\n          id\n        }\n      }\n    }\n\n    organismsBase: organisms {\n      label\n      id\n    }\n\n    organisms(where: { tableEntries_SOME: { guide: { name: $guideName } } }) {\n      id\n    }\n\n    selectableGuides: guides(\n      where: { name: $guideName, genome: { organism: { id_IN: $organismIds } } }\n    ) {\n      id\n      genome {\n        organism {\n          shortlabel\n        }\n      }\n    }\n  }\n": types.GuideAlignmentQueryDocument,
     "\n  query databaseStatisticsQuery {\n    organismsAggregate {\n      count\n    }\n\n    allModifications: modifications {\n      type\n    }\n\n    allModificationsCount: modificationsAggregate {\n      count\n    }\n\n    nonOrphanModificationsCount: modificationsAggregate(\n      where: { guidesAggregate: { count_GT: 0 } }\n    ) {\n      count\n    }\n\n    allGuides: guides {\n      subclass\n    }\n\n    allGuidesCount: guidesAggregate {\n      count\n    }\n\n    nonOrphanGuidesCount: guidesAggregate(\n      where: { modificationsAggregate: { count_GT: 0 } }\n    ) {\n      count\n    }\n  }\n": types.DatabaseStatisticsQueryDocument,
     "\n  query legalDocumentListQuery {\n    documents(where: { types_INCLUDES: \"legal\" }) {\n      id\n      menu_label\n    }\n  }\n": types.LegalDocumentListQueryDocument,
     "\n  query documentByIdQuery($id: ID) {\n    documents(where: { id: $id }) {\n      id\n      menu_label\n      content\n    }\n  }\n": types.DocumentByIdQueryDocument,
@@ -77,6 +79,14 @@ export function graphql(source: "\n  query targetByIdQuery($id: ID) {\n    targe
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
 export function graphql(source: "\n  query clusterByIdQuery($id: ID) {\n    clusters(where: { id: $id }) {\n      id\n      guides(options: { sort: [{ id: ASC }] }) {\n        id\n        name\n        class\n        subclass_label\n        modificationsAggregate {\n          count\n        }\n        chromosomeConnection: parentConnection(\n          where: { node: { graphql_type: Chromosome } }\n        ) {\n          edges {\n            properties {\n              start\n              end\n            }\n          }\n        }\n      }\n      guidesAggregate {\n        count\n      }\n      referenceGuide: guides(options: { limit: 1 }) {\n        chromosome: parent(where: { graphql_type: Chromosome }) {\n          id\n          name\n        }\n        genome {\n          organism {\n            label\n            id\n          }\n        }\n      }\n    }\n  }\n"): (typeof documents)["\n  query clusterByIdQuery($id: ID) {\n    clusters(where: { id: $id }) {\n      id\n      guides(options: { sort: [{ id: ASC }] }) {\n        id\n        name\n        class\n        subclass_label\n        modificationsAggregate {\n          count\n        }\n        chromosomeConnection: parentConnection(\n          where: { node: { graphql_type: Chromosome } }\n        ) {\n          edges {\n            properties {\n              start\n              end\n            }\n          }\n        }\n      }\n      guidesAggregate {\n        count\n      }\n      referenceGuide: guides(options: { limit: 1 }) {\n        chromosome: parent(where: { graphql_type: Chromosome }) {\n          id\n          name\n        }\n        genome {\n          organism {\n            label\n            id\n          }\n        }\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  query targetAlignmentQuery($targetName: String, $organismIds: [Int!]) {\n    targetBase: targets {\n      name\n      unit\n      genome {\n        organism {\n          id\n          label\n        }\n      }\n    }\n\n    organismsBase: organisms {\n      label\n      id\n    }\n\n    organisms(\n      where: {\n        tableEntries_SOME: { modification: { target: { name: $targetName } } }\n      }\n    ) {\n      id\n    }\n\n    selectableTargets: targets(\n      where: {\n        name: $targetName\n        genome: { organism: { id_IN: $organismIds } }\n      }\n    ) {\n      id\n      genome {\n        organism {\n          shortlabel\n        }\n      }\n    }\n  }\n"): (typeof documents)["\n  query targetAlignmentQuery($targetName: String, $organismIds: [Int!]) {\n    targetBase: targets {\n      name\n      unit\n      genome {\n        organism {\n          id\n          label\n        }\n      }\n    }\n\n    organismsBase: organisms {\n      label\n      id\n    }\n\n    organisms(\n      where: {\n        tableEntries_SOME: { modification: { target: { name: $targetName } } }\n      }\n    ) {\n      id\n    }\n\n    selectableTargets: targets(\n      where: {\n        name: $targetName\n        genome: { organism: { id_IN: $organismIds } }\n      }\n    ) {\n      id\n      genome {\n        organism {\n          shortlabel\n        }\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  query guideAlignmentQuery(\n    $guideSubclasses: [GuideClass!]\n    $guideName: String\n    $organismIds: [Int!]\n  ) {\n    guideBase: guides {\n      name\n      subclass\n      subclass_label\n      genome {\n        organism {\n          id\n        }\n      }\n    }\n\n    guideNamesFilteredBySubclass: guides(\n      where: { subclass_IN: $guideSubclasses }\n    ) {\n      name\n      genome {\n        organism {\n          id\n        }\n      }\n    }\n\n    organismsBase: organisms {\n      label\n      id\n    }\n\n    organisms(where: { tableEntries_SOME: { guide: { name: $guideName } } }) {\n      id\n    }\n\n    selectableGuides: guides(\n      where: { name: $guideName, genome: { organism: { id_IN: $organismIds } } }\n    ) {\n      id\n      genome {\n        organism {\n          shortlabel\n        }\n      }\n    }\n  }\n"): (typeof documents)["\n  query guideAlignmentQuery(\n    $guideSubclasses: [GuideClass!]\n    $guideName: String\n    $organismIds: [Int!]\n  ) {\n    guideBase: guides {\n      name\n      subclass\n      subclass_label\n      genome {\n        organism {\n          id\n        }\n      }\n    }\n\n    guideNamesFilteredBySubclass: guides(\n      where: { subclass_IN: $guideSubclasses }\n    ) {\n      name\n      genome {\n        organism {\n          id\n        }\n      }\n    }\n\n    organismsBase: organisms {\n      label\n      id\n    }\n\n    organisms(where: { tableEntries_SOME: { guide: { name: $guideName } } }) {\n      id\n    }\n\n    selectableGuides: guides(\n      where: { name: $guideName, genome: { organism: { id_IN: $organismIds } } }\n    ) {\n      id\n      genome {\n        organism {\n          shortlabel\n        }\n      }\n    }\n  }\n"];
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
diff --git a/src/gql/codegen/graphql.ts b/src/gql/codegen/graphql.ts
index f6673f5d2b9fc6cc764985ac33b49d0af780dee3..29a5f235a76b7ff9f6cc47b14a4f9332b33c0a2f 100644
--- a/src/gql/codegen/graphql.ts
+++ b/src/gql/codegen/graphql.ts
@@ -9829,6 +9829,23 @@ export type ClusterByIdQueryQueryVariables = Exact<{
 
 export type ClusterByIdQueryQuery = { __typename?: 'Query', clusters: Array<{ __typename?: 'Cluster', id: string, guides: Array<{ __typename?: 'Guide', id: string, name?: string | null, class: SequenceClass, subclass_label: string, modificationsAggregate?: { __typename?: 'GuideModificationModificationsAggregationSelection', count: number } | null, chromosomeConnection: { __typename?: 'GuideParentConnection', edges: Array<{ __typename?: 'GuideParentRelationship', properties: { __typename?: 'HasFeature', start: number, end: number } }> } }>, guidesAggregate?: { __typename?: 'ClusterGuideGuidesAggregationSelection', count: number } | null, referenceGuide: Array<{ __typename?: 'Guide', chromosome?: { __typename?: 'Chromosome', id: string, name?: string | null } | { __typename?: 'GenericSequence', id: string, name?: string | null } | { __typename?: 'Guide', id: string, name?: string | null } | { __typename?: 'Target', id: string, name?: string | null } | null, genome?: { __typename?: 'Genome', organism?: { __typename?: 'Organism', label: string, id: number } | null } | null }> }> };
 
+export type TargetAlignmentQueryQueryVariables = Exact<{
+  targetName?: InputMaybe<Scalars['String']['input']>;
+  organismIds?: InputMaybe<Array<Scalars['Int']['input']> | Scalars['Int']['input']>;
+}>;
+
+
+export type TargetAlignmentQueryQuery = { __typename?: 'Query', targetBase: Array<{ __typename?: 'Target', name?: string | null, unit?: string | null, genome?: { __typename?: 'Genome', organism?: { __typename?: 'Organism', id: number, label: string } | null } | null }>, organismsBase: Array<{ __typename?: 'Organism', label: string, id: number }>, organisms: Array<{ __typename?: 'Organism', id: number }>, selectableTargets: Array<{ __typename?: 'Target', id: string, genome?: { __typename?: 'Genome', organism?: { __typename?: 'Organism', shortlabel: string } | null } | null }> };
+
+export type GuideAlignmentQueryQueryVariables = Exact<{
+  guideSubclasses?: InputMaybe<Array<GuideClass> | GuideClass>;
+  guideName?: InputMaybe<Scalars['String']['input']>;
+  organismIds?: InputMaybe<Array<Scalars['Int']['input']> | Scalars['Int']['input']>;
+}>;
+
+
+export type GuideAlignmentQueryQuery = { __typename?: 'Query', guideBase: Array<{ __typename?: 'Guide', name?: string | null, subclass: GuideClass, subclass_label: string, genome?: { __typename?: 'Genome', organism?: { __typename?: 'Organism', id: number } | null } | null }>, guideNamesFilteredBySubclass: Array<{ __typename?: 'Guide', name?: string | null, genome?: { __typename?: 'Genome', organism?: { __typename?: 'Organism', id: number } | null } | null }>, organismsBase: Array<{ __typename?: 'Organism', label: string, id: number }>, organisms: Array<{ __typename?: 'Organism', id: number }>, selectableGuides: Array<{ __typename?: 'Guide', id: string, genome?: { __typename?: 'Genome', organism?: { __typename?: 'Organism', shortlabel: string } | null } | null }> };
+
 export type DatabaseStatisticsQueryQueryVariables = Exact<{ [key: string]: never; }>;
 
 
@@ -9856,6 +9873,8 @@ export const ModificationByIdQueryDocument = {"kind":"Document","definitions":[{
 export const GuideByIdQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"guideByIdQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"guides"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"altnames"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"length"}},{"kind":"Field","name":{"kind":"Name","value":"class"}},{"kind":"Field","name":{"kind":"Name","value":"subclass_label"}},{"kind":"Field","alias":{"kind":"Name","value":"chromosomeConnection"},"name":{"kind":"Name","value":"parentConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"node"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"graphql_type"},"value":{"kind":"EnumValue","value":"Chromosome"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}},{"kind":"Field","name":{"kind":"Name","value":"strand"}}]}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"length"}},{"kind":"Field","name":{"kind":"Name","value":"graphql_type"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"host_genes"}},{"kind":"Field","name":{"kind":"Name","value":"seq"}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"boxConnections"},"name":{"kind":"Name","value":"featuresConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"NOT"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"node"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"class"},"value":{"kind":"EnumValue","value":"DuplexFragment"}}]}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"HasFeature"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"annotation"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"modifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"options"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"sort"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"position"},"value":{"kind":"EnumValue","value":"ASC"}}]}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"Field","name":{"kind":"Name","value":"modificationsAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"interactions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"duplexes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"primaryStrandsConnection"},"name":{"kind":"Name","value":"strandsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"edge"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"primary"},"value":{"kind":"BooleanValue","value":true}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}},{"kind":"Field","name":{"kind":"Name","value":"primary"}}]}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"seq"}},{"kind":"Field","name":{"kind":"Name","value":"parentConnection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}}]}}]}}]}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"secondaryStrandsConnection"},"name":{"kind":"Name","value":"strandsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"edge"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"primary"},"value":{"kind":"BooleanValue","value":false}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}},{"kind":"Field","name":{"kind":"Name","value":"primary"}}]}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"seq"}},{"kind":"Field","name":{"kind":"Name","value":"parentConnection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}}]}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"index"}}]}},{"kind":"Field","name":{"kind":"Name","value":"modification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"symbol"}},{"kind":"Field","name":{"kind":"Name","value":"symbol_label"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"type_short_label"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"class"}},{"kind":"Field","name":{"kind":"Name","value":"unit"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"cluster"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"clusterAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isoform"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"guides"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"guidesAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"isoformAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"chebi_id"}},{"kind":"Field","name":{"kind":"Name","value":"so_id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"modifications_SOME"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"guides_SOME"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"options"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"sort"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name"},"value":{"kind":"EnumValue","value":"ASC"}}]}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"class"}},{"kind":"Field","name":{"kind":"Name","value":"unit"}}]}}]}}]} as unknown as DocumentNode<GuideByIdQueryQuery, GuideByIdQueryQueryVariables>;
 export const TargetByIdQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"targetByIdQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"targets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"altnames"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"length"}},{"kind":"Field","name":{"kind":"Name","value":"class"}},{"kind":"Field","name":{"kind":"Name","value":"unit"}},{"kind":"Field","alias":{"kind":"Name","value":"chromosomeConnection"},"name":{"kind":"Name","value":"parentConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"node"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"graphql_type"},"value":{"kind":"EnumValue","value":"Chromosome"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}},{"kind":"Field","name":{"kind":"Name","value":"strand"}}]}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"graphql_type"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"seq"}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"modifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"options"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"sort"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"position"},"value":{"kind":"EnumValue","value":"ASC"}}]}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"symbol"}}]}},{"kind":"Field","name":{"kind":"Name","value":"modificationsAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"interactions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"duplexes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"primaryStrandsConnection"},"name":{"kind":"Name","value":"strandsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"edge"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"primary"},"value":{"kind":"BooleanValue","value":true}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}},{"kind":"Field","name":{"kind":"Name","value":"primary"}}]}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"seq"}},{"kind":"Field","name":{"kind":"Name","value":"parentConnection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}}]}}]}}]}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"secondaryStrandsConnection"},"name":{"kind":"Name","value":"strandsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"edge"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"primary"},"value":{"kind":"BooleanValue","value":false}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}},{"kind":"Field","name":{"kind":"Name","value":"primary"}}]}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"seq"}},{"kind":"Field","name":{"kind":"Name","value":"parentConnection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}}]}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"index"}}]}},{"kind":"Field","name":{"kind":"Name","value":"modification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"symbol"}},{"kind":"Field","name":{"kind":"Name","value":"symbol_label"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"type_short_label"}}]}},{"kind":"Field","name":{"kind":"Name","value":"guide"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"subclass_label"}},{"kind":"Field","name":{"kind":"Name","value":"class"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"chebi_id"}},{"kind":"Field","name":{"kind":"Name","value":"so_id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"secondary_struct_file"}}]}},{"kind":"Field","name":{"kind":"Name","value":"guides"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"modifications_SOME"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"target"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"options"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"sort"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"EnumValue","value":"ASC"}}]}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"class"}},{"kind":"Field","alias":{"kind":"Name","value":"chromosome"},"name":{"kind":"Name","value":"parent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"graphql_type"},"value":{"kind":"EnumValue","value":"Chromosome"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode<TargetByIdQueryQuery, TargetByIdQueryQueryVariables>;
 export const ClusterByIdQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"clusterByIdQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"clusters"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"guides"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"options"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"sort"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"EnumValue","value":"ASC"}}]}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"class"}},{"kind":"Field","name":{"kind":"Name","value":"subclass_label"}},{"kind":"Field","name":{"kind":"Name","value":"modificationsAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"chromosomeConnection"},"name":{"kind":"Name","value":"parentConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"node"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"graphql_type"},"value":{"kind":"EnumValue","value":"Chromosome"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"properties"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"guidesAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"referenceGuide"},"name":{"kind":"Name","value":"guides"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"options"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"chromosome"},"name":{"kind":"Name","value":"parent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"graphql_type"},"value":{"kind":"EnumValue","value":"Chromosome"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<ClusterByIdQueryQuery, ClusterByIdQueryQueryVariables>;
+export const TargetAlignmentQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"targetAlignmentQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"targetName"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organismIds"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"targetBase"},"name":{"kind":"Name","value":"targets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"unit"}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}}]}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"organismsBase"},"name":{"kind":"Name","value":"organisms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"organisms"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"tableEntries_SOME"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"modification"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"target"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"targetName"}}}]}}]}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"selectableTargets"},"name":{"kind":"Name","value":"targets"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"targetName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"genome"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"organism"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id_IN"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organismIds"}}}]}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"shortlabel"}}]}}]}}]}}]}}]} as unknown as DocumentNode<TargetAlignmentQueryQuery, TargetAlignmentQueryQueryVariables>;
+export const GuideAlignmentQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"guideAlignmentQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"guideSubclasses"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GuideClass"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"guideName"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"organismIds"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"guideBase"},"name":{"kind":"Name","value":"guides"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"subclass"}},{"kind":"Field","name":{"kind":"Name","value":"subclass_label"}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"guideNamesFilteredBySubclass"},"name":{"kind":"Name","value":"guides"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"subclass_IN"},"value":{"kind":"Variable","name":{"kind":"Name","value":"guideSubclasses"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"organismsBase"},"name":{"kind":"Name","value":"organisms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"organisms"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"tableEntries_SOME"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"guide"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"guideName"}}}]}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"selectableGuides"},"name":{"kind":"Name","value":"guides"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"guideName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"genome"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"organism"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id_IN"},"value":{"kind":"Variable","name":{"kind":"Name","value":"organismIds"}}}]}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"genome"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organism"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"shortlabel"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GuideAlignmentQueryQuery, GuideAlignmentQueryQueryVariables>;
 export const DatabaseStatisticsQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"databaseStatisticsQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"organismsAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"allModifications"},"name":{"kind":"Name","value":"modifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"allModificationsCount"},"name":{"kind":"Name","value":"modificationsAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"nonOrphanModificationsCount"},"name":{"kind":"Name","value":"modificationsAggregate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"guidesAggregate"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"count_GT"},"value":{"kind":"IntValue","value":"0"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"allGuides"},"name":{"kind":"Name","value":"guides"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subclass"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"allGuidesCount"},"name":{"kind":"Name","value":"guidesAggregate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"nonOrphanGuidesCount"},"name":{"kind":"Name","value":"guidesAggregate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"modificationsAggregate"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"count_GT"},"value":{"kind":"IntValue","value":"0"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]} as unknown as DocumentNode<DatabaseStatisticsQueryQuery, DatabaseStatisticsQueryQueryVariables>;
 export const LegalDocumentListQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"legalDocumentListQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"types_INCLUDES"},"value":{"kind":"StringValue","value":"legal","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"menu_label"}}]}}]}}]} as unknown as DocumentNode<LegalDocumentListQueryQuery, LegalDocumentListQueryQueryVariables>;
 export const DocumentByIdQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"documentByIdQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"documents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"menu_label"}},{"kind":"Field","name":{"kind":"Name","value":"content"}}]}}]}}]} as unknown as DocumentNode<DocumentByIdQueryQuery, DocumentByIdQueryQueryVariables>;
\ No newline at end of file
diff --git a/src/gql/queries.ts b/src/gql/queries.ts
index 8c4c412ba4937932b616a9469b7de77ebeac4e49..ba8c44dad3a7f2cb480e63e087c7f808893ee456 100644
--- a/src/gql/queries.ts
+++ b/src/gql/queries.ts
@@ -820,6 +820,104 @@ export const clusterByIdQuery = graphql(/* GraphQL */ `
   }
 `)
 
+/**
+ * Get necessary data to select sequences for alignment.
+ */
+export const targetAlignmentQuery = graphql(/* GraphQL */ `
+  query targetAlignmentQuery($targetName: String, $organismIds: [Int!]) {
+    targetBase: targets {
+      name
+      unit
+      genome {
+        organism {
+          id
+          label
+        }
+      }
+    }
+
+    organismsBase: organisms {
+      label
+      id
+    }
+
+    organisms(
+      where: {
+        tableEntries_SOME: { modification: { target: { name: $targetName } } }
+      }
+    ) {
+      id
+    }
+
+    selectableTargets: targets(
+      where: {
+        name: $targetName
+        genome: { organism: { id_IN: $organismIds } }
+      }
+    ) {
+      id
+      genome {
+        organism {
+          shortlabel
+        }
+      }
+    }
+  }
+`)
+
+/**
+ * Get necessary data to select sequences for alignment.
+ */
+export const guideAlignmentQuery = graphql(/* GraphQL */ `
+  query guideAlignmentQuery(
+    $guideSubclasses: [GuideClass!]
+    $guideName: String
+    $organismIds: [Int!]
+  ) {
+    guideBase: guides {
+      name
+      subclass
+      subclass_label
+      genome {
+        organism {
+          id
+        }
+      }
+    }
+
+    guideNamesFilteredBySubclass: guides(
+      where: { subclass_IN: $guideSubclasses }
+    ) {
+      name
+      genome {
+        organism {
+          id
+        }
+      }
+    }
+
+    organismsBase: organisms {
+      label
+      id
+    }
+
+    organisms(where: { tableEntries_SOME: { guide: { name: $guideName } } }) {
+      id
+    }
+
+    selectableGuides: guides(
+      where: { name: $guideName, genome: { organism: { id_IN: $organismIds } } }
+    ) {
+      id
+      genome {
+        organism {
+          shortlabel
+        }
+      }
+    }
+  }
+`)
+
 /**
  * Get statistics about the database.
  */
diff --git a/src/layouts/FooterLayout.vue b/src/layouts/FooterLayout.vue
index b8b9b65f243c0bbdb24db3f827b1ef4222b926e5..40c65ef5e1201d99a8ca122d0149b7d9fad79625 100644
--- a/src/layouts/FooterLayout.vue
+++ b/src/layouts/FooterLayout.vue
@@ -11,7 +11,7 @@ import Button from 'primevue/button'
 import IconFa6SolidAddressCard from '~icons/fa6-solid/address-card'
 import IconFa6SolidChevronUp from '~icons/fa6-solid/chevron-up'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
 /**
diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue
index b7e4fc416d89a519a23fbb24fb6a69bac533dcfc..1be2df3923fde964a1d8950fb9e7157883a2e3ae 100644
--- a/src/layouts/MainLayout.vue
+++ b/src/layouts/MainLayout.vue
@@ -3,7 +3,6 @@
  * Vue imports
  */
 import { ref } from 'vue'
-import { useRouter } from 'vue-router'
 /**
  * Components imports
  */
@@ -15,6 +14,10 @@ import Menubar from 'primevue/menubar'
 import IconFa6SolidMagnifyingGlass from '~icons/fa6-solid/magnifying-glass'
 import IconFa6SolidCircleXmark from '~icons/fa6-solid/circle-xmark'
 import IconFa6SolidArrowRight from '~icons/fa6-solid/arrow-right'
+/**
+ * Composables imports
+ */
+import { useRouter } from 'vue-router'
 /**
  * Utils imports
  */
diff --git a/src/router/index.ts b/src/router/index.ts
index f29dd5bb5bb141619f0c57f083dbdc477b08ec3f..b12de9de6a7de5ad7905aa931aee98a2d5b3491e 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -7,18 +7,22 @@ import { createRouter, createWebHistory } from 'vue-router'
  */
 import HomeView from '@/views/HomeView.vue'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
 import { isNonNullish } from '@/typings/typeUtils'
 /**
  * Types imports
  */
-import type { SelectionFormModesType } from '@/views/SelectionView.vue'
+import type { SelectionModesType } from '@/views/SelectionView.vue'
+// import type { AlignmentModesType } from '@/views/AlignmentView.vue'
 /**
  * Utils imports
  */
-import { SELECTION_FORM_MODES } from '@/utils/constant'
+import { /* ALIGNMENT_MODES, */ SELECTION_MODES } from '@/utils/constant'
 
 declare module 'vue-router' {
   interface RouteMeta {
@@ -42,20 +46,18 @@ const router = createRouter({
       name: 'selection',
       component: () => import('@/views/SelectionView.vue'),
       props: (to) => ({
-        mode: to.query.mode
+        initialMode: to.query.mode
       }),
       beforeEnter: (to) => {
         if (
           typeof to.query.mode !== 'string' ||
-          !SELECTION_FORM_MODES.includes(
-            to.query.mode as SelectionFormModesType
-          )
+          !SELECTION_MODES.includes(to.query.mode as SelectionModesType)
         ) {
-          router.replace({ name: 'lost' })
+          router.replace({ name: 'selection', query: { mode: 'guide' } })
         }
       },
       meta: {
-        title: 'Advanced selection'
+        managedTitle: true
       }
     },
     {
@@ -109,6 +111,9 @@ const router = createRouter({
         ) {
           router.replace({ name: 'notFound' })
         }
+      },
+      meta: {
+        managedTitle: true
       }
     },
     {
@@ -132,6 +137,9 @@ const router = createRouter({
             if (typeof to.query.id !== 'string') {
               router.replace({ name: 'notFound' })
             }
+          },
+          meta: {
+            managedTitle: true
           }
         },
         {
@@ -146,6 +154,9 @@ const router = createRouter({
             if (typeof to.query.id !== 'string') {
               router.replace({ name: 'notFound' })
             }
+          },
+          meta: {
+            managedTitle: true
           }
         },
         {
@@ -160,6 +171,9 @@ const router = createRouter({
             if (typeof to.query.id !== 'string') {
               router.replace({ name: 'notFound' })
             }
+          },
+          meta: {
+            managedTitle: true
           }
         },
         {
@@ -171,10 +185,32 @@ const router = createRouter({
             if (typeof to.query.id !== 'string') {
               router.replace({ name: 'notFound' })
             }
+          },
+          meta: {
+            managedTitle: true
           }
         }
       ]
     },
+    // {
+    //   path: '/alignment',
+    //   name: 'alignment',
+    //   component: () => import('@/views/AlignmentView.vue'),
+    //   props: (to) => ({
+    //     initialMode: to.query.mode
+    //   }),
+    //   beforeEnter: (to) => {
+    //     if (
+    //       typeof to.query.mode !== 'string' ||
+    //       !ALIGNMENT_MODES.includes(to.query.mode as AlignmentModesType)
+    //     ) {
+    //       router.replace({ name: 'alignment', query: { mode: 'guide' } })
+    //     }
+    //   },
+    //   meta: {
+    //     managedTitle: true
+    //   }
+    // },
     {
       path: '/statistics',
       name: 'statistics',
@@ -263,8 +299,10 @@ const router = createRouter({
 })
 
 router.afterEach((to) => {
-  useTitle((to.meta.title ? `${to.meta.title} | ` : '') + 'SnoBoard')
-  console.info('Title changed.')
+  if (!to.meta.managedTitle) {
+    useTitle((to.meta.title ? `${to.meta.title} | ` : '') + 'SnoBoard')
+    console.info('Title changed.')
+  }
 })
 
 export default router
diff --git a/src/typings/typeUtils.ts b/src/typings/typeUtils.ts
index d44a1907db913128da2440626b8e95b317986e1f..d23a9f3ca3a829b9da9dbd532febf9e152bc4c57 100644
--- a/src/typings/typeUtils.ts
+++ b/src/typings/typeUtils.ts
@@ -110,3 +110,11 @@ export type SubType<BaseType, ConditionType> = Pick<
     [Key in keyof BaseType]: BaseType[Key] extends ConditionType ? Key : never
   }[keyof BaseType]
 >
+
+/**
+ * Checks if an array contains at least one element, narrowing its type.
+ * @param array The array for which to check the length.
+ */
+export function isNotEmpty<T>(array: T[]): array is [T,...T[]] {
+  return array.length >= 1
+}
\ No newline at end of file
diff --git a/src/utils/constant.ts b/src/utils/constant.ts
index 0b0b8efa33038c101af9aa6c12c025a1443015f9..6aaf040b1448c319ec0d35540a6bf70a091772f1 100644
--- a/src/utils/constant.ts
+++ b/src/utils/constant.ts
@@ -1,5 +1,5 @@
 /**
- * Component imports
+ * Components imports
  */
 import IconFa6SolidTable from '~icons/fa6-solid/table'
 import IconFa6SolidDatabase from '~icons/fa6-solid/database'
@@ -36,10 +36,14 @@ interface HelpTourItem {
 }
 
 /**
- * The different modes available for advanced selection form on the selection
- * page.
+ * The different modes available for advanced selection.
  */
-export const SELECTION_FORM_MODES = ['modification', 'guide', 'target'] as const
+export const SELECTION_MODES = ['modification', 'guide', 'target'] as const
+
+/**
+ * The different modes available for alignment.
+ */
+export const ALIGNMENT_MODES = ['guide', 'target'] as const
 
 /**
  * The items to display in the main navigation menu.
diff --git a/src/utils/graphFormat.ts b/src/utils/graphFormat.ts
index 70e62750ecb3af9d425591e48452df58b99a7fe8..aedd4cfdfb1bb1706ca2ad142db1593d667dfe40 100644
--- a/src/utils/graphFormat.ts
+++ b/src/utils/graphFormat.ts
@@ -1,5 +1,9 @@
-import type { C4GGraphModel, C4GNodeModel } from '@/typings/Codev4GraphFormat'
+/**
+ * Types imports
+ */
+import type { C4GGraphModel } from '@/typings/Codev4GraphFormat'
 import type { JGFGraphModel } from '@/typings/JSONGraphFormat'
+import { mapValues as _mapValues } from 'lodash-es'
 
 /**
  * "Fix" a graph by transforming it to proper C4G format
@@ -22,30 +26,22 @@ export const fixGraphFormat = (JGFGraph: JGFGraphModel): C4GGraphModel => {
           })
         )
       },
-      nodes: Object.entries(JGFGraph.graph.nodes || {}).reduce<{
-        [nodeId: string]: C4GNodeModel
-      }>(
-        (nodes, [nodeId, node]) => ({
-          ...nodes,
-          [nodeId]: {
-            label: node.label,
-            metadata: {
-              position: {
-                x: node.metadata?.x,
-                y: node.metadata?.y
-              },
-              data: [
-                {
-                  label: 'nucleotidePosition',
-                  type: 'number',
-                  value: node.metadata?.position
-                }
-              ]
+      nodes: _mapValues(JGFGraph.graph.nodes, (node) => ({
+        label: node.label,
+        metadata: {
+          position: {
+            x: node.metadata?.x,
+            y: node.metadata?.y
+          },
+          data: [
+            {
+              label: 'nucleotidePosition',
+              type: 'number',
+              value: node.metadata?.position
             }
-          }
-        }),
-        {}
-      ),
+          ]
+        }
+      })),
       edges: JGFGraph.graph.edges?.map((edge) => ({
         ...edge,
         metadata: {
diff --git a/src/utils/normalise.ts b/src/utils/normalise.ts
index b6f9a32aef922969c7bc17dab3f93db4ddd0b08c..18f945dd9bdee923f680aff2eec33968642ed30d 100644
--- a/src/utils/normalise.ts
+++ b/src/utils/normalise.ts
@@ -1,7 +1,7 @@
 /**
  * Other 3rd-party imports
  */
-import { findIndex as _findIndex } from 'lodash-es'
+import { findIndex as _findIndex, mapValues as _mapValues } from 'lodash-es'
 /**
  * Types imports
  */
@@ -96,9 +96,7 @@ export const composeNormalisedGraph = (
     normalisedEdgeLength / (referenceEdgeLength || normalisedEdgeLength)
 
   // Apply normalisation to the nodes
-  const normalisedNodes = Object.entries(graph.graph.nodes).reduce<{
-    [nodeId: string]: C4GNodeModel
-  }>((nodes, [nodeId, node]) => {
+  const normalisedNodes = _mapValues(graph.graph.nodes, (node) => {
     // Normalise position if present
     const normalisedNode = node.metadata?.position
       ? {
@@ -116,10 +114,7 @@ export const composeNormalisedGraph = (
     // Check if additional metadata is present, if not return & continue
     // normalisation on next node
     if (!normalisedNode.metadata?.data) {
-      return {
-        ...nodes,
-        [`${nodeId}`]: normalisedNode
-      }
+      return normalisedNode
     }
 
     // Get indexes of additional metadata to normalise (-1 if not present)
@@ -166,11 +161,8 @@ export const composeNormalisedGraph = (
       nucleotidePositionLineDataValue.y2 *= normalisationRatio
     }
 
-    return {
-      ...nodes,
-      [`${nodeId}`]: normalisedNode
-    }
-  }, {})
+    return normalisedNode
+  })
 
   return {
     graph: {
diff --git a/src/utils/sequences.ts b/src/utils/sequences.ts
new file mode 100644
index 0000000000000000000000000000000000000000..24412249a8fb4411ce855f717d3f6bb9ea440b48
--- /dev/null
+++ b/src/utils/sequences.ts
@@ -0,0 +1,15 @@
+/**
+ * In an array of sequences (e.g. for an alignment), computes the conservation
+ * rate of a reference seq., i.e. the proportion of seq. in the array which are
+ * identical to it.
+ * @param sequences The sequences among which to compute the conservation.
+ * @param referenceSequence The sequence for which to compute the conservation.
+ * @returns The proportion of the sequences in the array which are identical to
+ * the reference one.
+ */
+export const composeConservationRate = (
+  sequences: string[],
+  referenceSequence: string
+): number =>
+  sequences.filter((sequence) => sequence && sequence === referenceSequence)
+    .length / (sequences.length || 1)
diff --git a/src/views/APIView.vue b/src/views/APIView.vue
index 73bdbca3897e35d921c08f8c947aed8adb05c0a8..b98200b0ce02a7297f4c3dd6a3879d23fc259844 100644
--- a/src/views/APIView.vue
+++ b/src/views/APIView.vue
@@ -12,11 +12,14 @@ import Dialog from 'primevue/dialog'
 import Checkbox from 'primevue/checkbox'
 import IconDeviconNeo4j from '~icons/devicon/neo4j'
 import IconLogosGraphql from '~icons/logos/graphql'
+/**
+ * Composables imports
+ */
+import { useStorage } from '@vueuse/core'
 /**
  * Other 3rd-party imports
  */
 import { ApolloSandbox } from '@apollo/sandbox'
-import { useStorage } from '@vueuse/core'
 
 /**
  * Reactive local storage entry to show or not the info dialog at landing.
diff --git a/src/views/AlignmentView.vue b/src/views/AlignmentView.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f9dad3e1bc59d45d4f3895b687ea04721f7721c4
--- /dev/null
+++ b/src/views/AlignmentView.vue
@@ -0,0 +1,179 @@
+<script setup lang="ts">
+/**
+ * Vue imports
+ */
+import { computed, ref, onMounted } from 'vue'
+/**
+ * Components imports
+ */
+import MainLayout from '@/layouts/MainLayout.vue'
+import SequenceAlignment from '@/components/SequenceAlignment.vue'
+import AlignmentForm from '@/components/AlignmentForm.vue'
+import IconSnoboardAlignment from '~icons/snoboard/alignment'
+/**
+ * Composables imports
+ */
+import { useRouter } from 'vue-router'
+import { useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party import
+ */
+import { capitalize as _capitalize } from 'lodash-es'
+/**
+ * Type imports
+ */
+import type { AlignmentModel } from '@/components/SequenceAlignment.vue'
+/**
+ * Utils imports
+ */
+import { ALIGNMENT_MODES } from '@/utils/constant'
+
+/**
+ * Type of sequence to align.
+ */
+export type AlignmentModesType = (typeof ALIGNMENT_MODES)[number]
+
+const ALIGNMENT: AlignmentModel = {
+  tracks: [
+    {
+      id: '18S_Arabidopsis_Iour',
+      name: 'A.thaliana - Iouri',
+      shortname: 'Ath-I',
+      sequence:
+        'UACCUGGUUGAUCCUGCCAGUAGUCAUAUGCUUGUCUCAAAGAUUAAGCCAUGCAUGUGUAAGUAUGAACGAAUUCAGACUGUGAAACUGCGAAUGGCUCAUUAAAUCAGUUAUAGUUUGUUUGAUGGUAA---CUACUACUC---GGAUAACCGUAGUAAUUCUAGAGCUAAUACGUGCAAC---------AAACCCCGACU-UAUGGAAGGGACGCAUUUAUUAGAUAAAAG----------------------------GUCGACGCGGGCUCUGCCCGUUGCUCUGAUGAUUCAUGAUAACUC--GACGGAUCGCAUGGCCUCUGUGCUGGCGACGCAUCAUUCAAAUUUCUGCCCUAUCAACUUUCGAUGGUAGGAUAGUGGCCUACCAUGGUGGUAACGGGUGACGGAGAAUUAGGGUUCGAUUCCGGAGAGGGAGCCUGAGAAACGGCUACCACAUCCAAGGAAGGCAGCAGGCGCGCAAAUUACCCAAUCCUGACACGGGGAGGUAGUGACAAUAAAUAACAAUACCGGGCUCUUUCGAGUCU-GGUAAUUGGAAUGAGUACAAUCUAAAUCCCUUAACGAGGAUCCAUUGGAGGGCAAGUCUGGUGCCAGCAGCCGCGGUAAUUCCAGCUCCAAUAGCGUAUAUUUAAGUUGUUGCAGUUAAAAAGCUCGUAGUUGAACCUUGGGAUGGGUCGGCCGGUCCGCCUUUGGUGUGCAUUGGUC--------GGCUUGUCCCUUCGGUCGGCGAUACGCUCCUGGUCUUAAUUGGCCGGGUCGUGCCUCCGGCGCUGUUACUUUGAAGAAAUUAGAGUGCUCAAAGCAAGCCUACGCU--CUGGAUACAUUAGCAUGGGAUAACAUCAUAGGAU-UUCGAUCCUAUUGUGUUGGCCUUCGGGAUCGGAGUAAUGAUUAACAGGGACAGUCGGGGGCAUUCGUAUUUCAUAGUCAGAGGUGAAAUUCUUGGAUUUAUGAAAGACGAACAACUGCGAAAGCAUUUGCCAAGGAUGUUUUCAUUAAUCAAGAACGAAAGUUGGGGGCUCGAAGACGAUCAGAUACCGUCCUAGUCUCAACCAUAAACGAUGCCGACCAGGGAUCAGCGGAUGUUGCUUAUAGGACUCCGCUGGCACCUUAUGAGAAAUCAAAGUUUUUGGGUUCCGGGGGGAGUAUGGUCGCAAGGCUGAAACUUAAAGGAAUUGACGGAAGGGCACCACCAGGAGUGGAGCCUGCGGCUUAAUUUGACUCAACACGGGGAAACUUACCAGGUCCAGACAUAGUAAGGAUUGACAGACUGAGAGCUCUUUCUUGAUUCUAUGGGUGGUGGUGCAUGGCCGUUCUUAGUUGGUGGAGCGAUUUGUCUGGUUAAUUCCGUUAACGAACGAGACCUCAGCCUGCUAACUAGCUACGUG-----GAGGCAUCCCUUCACGGCCGGCUUCUUAGAGGGACUAUGGCCGUUUAGGCCAAGGAAGUUUGAGGCAAUAACAGGUCUGUGAUGCCCUUAGAUGUUCUGGGCCGCACGCGCGCUACACUGAUGUAUUCAACGAGUUCACACCUUG-GCCGACAGGCCCGGGUAAUCUU-UGAAAUUUCAUCGUGAUGGGGAUAGAUCAUUGCAAUUGUUGGUCUUCAACGAGGAAUUCCU--AGUAAGCGCGAGUCAUCAGCUCGCGUUGACUACGUCCCUGCCCUUUGUACACACCGCCCGUCGCUCCUACCGAUUGAAUGAUCCGGUGAAGUGUUCGGAUCGCGGCGACGUGGGUGGUUCGCCGCCC---GCGACGUCGCGAGAAGUCCACUAAACCUUAUCAUUUAGAGGAAGGAGAAGUCGUAACAAGGUUUCCGUAGGUGAACCUGCGGAAGGAUCAUUG',
+      isReference: true,
+      objects: {
+        MOD_00030: {
+          name: 'Am28_18S',
+          start: 28,
+          end: 28,
+          type: "2'-*O*-Me",
+          color: 'sky',
+          link: { name: 'modificationDetails', query: { id: 'MOD_00030' } }
+        },
+        MOD_00187: {
+          name: 'Psi35_18S',
+          start: 35,
+          end: 35,
+          type: 'Pseudouridylation',
+          color: 'violet',
+          link: { name: 'modificationDetails', query: { id: 'MOD_00187' } }
+        },
+        MOD_00012: {
+          name: 'Am162_18S',
+          start: 168,
+          end: 168,
+          type: "2'-*O*-Me",
+          color: 'sky',
+          link: { name: 'modificationDetails', query: { id: 'MOD_00012' } }
+        }
+      }
+    },
+    {
+      id: '18S_Arabidopsis_thal',
+      name: 'A.thaliana - ref',
+      shortname: 'Ath-Ref',
+      sequence:
+        'UACCUGGUUGAUCCUGCCAGUAGUCAUAUGCUUGUCUCAAAGAUUAAGCCAUGCAUGUGUAAGUAUGAACGAAUUCAGACUGUGAAACUGCGAAUGGCUCAUUAAAUCAGUUAUAGUUUGUUUGAUGGUAA---CUACUACUC---GGAUAACCGUAGUAAUUCUAGAGCUAAUACGUGCAAC---------AAACCCCGACU-UAUGGAAGGGACGCAUUUAUUAGAUAAAAG----------------------------GUCGACGCGGGCUCUGGC--UUGCUCUGAUGAUUCAUGAUAACUC--GACGGAUCGCAUGGCCUCUGUGCUGGCGACGCAUCAUUCAAAUUUCUGCCCUAUCAACUUUCGAUGGUAGGAUAGUGGCCUACCAUGGUGGUAACGGGUGACGGAGAAUUAGGGUUCGAUUCCGGAGAGGGAGCCUGAGAAACGGCUACCACAUCCAAGGAAGGCAGCAGGCGCGCAAAUUACCCAAUCCUGACACGGGGAGGUAGUGACAAUAAAUAACAAUACCGGGCUCUUUCGAGUCU-GGUAAUUGGAAUGAGUACAAUCUAAAUCCCUUAACGAGGAUCCAUUGGAGGGCAAGUCUGGUGCCAGCAGCCGCGGUAAUUCCAGCUCCAAUAGCGUAUAUUUAAGUUGUUGCAGUUAAAAAGCUCGUAGUUGAACCUUGGGAUGGGUCGGCCGGUCCGCCUUUGGUGUGCAUUGGUC--------GGCUUGUCCCUUCGGUCGGCGAUACGCUCCUGGUCUUAAUUGGCCGGGUCGUGCCUCCGGCGCUGUUACUUUGAAGAAAUUAGAGUGCUCAAAGCAAGCCUACGCU--CUGGAUACAUUAGCAUGGGAUAACAUCAUAGGAU-UUCGAUCCUAUUGUGUUGGC-UUCGGGAUCGGAGUAAUGAUUAACAGGGACAGUCGGGGGCAUUCGUAUUUCAUAGUCAGAGGUGAAAUUCUUGGAUUUAUGAAAGACGAACAACUGCGAAAGCAUUUGCCAAGGAUGUUUUCAUUAAUCAAGAACGAAAGUUGGGGGCUCGAAGACGAUCAGAUACCGUCCUAGUCUCAACCAUAAACGAUGCCGACCAGGGAUCAGCGGAUGUUGCUUAUAGGACUCCGCUGGCACCUUAUGAGAAAUCAAAGUUUUUGGGUUCCGGGGGGAGUAUGGUCGCAAGGCUGAAACUUAAAGGAAUUGACGGAAGGGCACCACCAGGAGUGGAGCCUGCGGCUUAAUUUGACUCAACACGGGGAAACUUACCAGGUCCAGACAUAGUAAGGAUUGACAGACUGAGAGCUCUUUCUUGAUUCUAUGGGUGGUGGUGCAUGGCCGUUCUUAGUUGGUGGAGCGAUUUGUCUGGUUAAUUCCGUUAACGAACGAGACCUCAGCCUGCUAACUAGCUACGUG-----GAGGCAUCCCUUCACGGCCGGCUUCUUAGAGGGACUAUGGCCGUUUAGGCCAAGGAAGUUUGAGGCAAUAACAGGUCUGUGAUGCCCUUAGAUGUUCUGGGCCGCACGCGCGCUACACUGAUGUAUUCAACGAGUUCACACCUUG--CCGACAGGCCCGGGUAAUCUU-UGAAAUUUCAUCGUGAUGGGGAUAGAUCAUUGCAAUUGUUGGUCUUCAACGAGGAAUUCCU--AGUAAGCGCGAGUCAUCAGCUCGCGUUGACUACGUCCCUGCCCUUUGUACACACCGCCCGUCGCUCCUACCGAUUGAAUGAUCCGGUGAAGUGUUCGGAUCGCGGCGACGUGGGUGGUUCGCCGCCC---GCGACGUCGCGAGAAGUCCACUAAACCUUAUCAUUUAGAGGAAGGAGAAGUCGUAACAAGGUUUCCGUAGGUGAACCUGCGGAAGGAUCAUUG'
+    },
+    {
+      id: '18S_S.cerevisiae',
+      name: 'S.cerevisiae - ref',
+      shortname: 'Sc-Ref',
+      sequence:
+        'UAUCUGGUUGAUCCUGCCAGUAGUCAUAUGCUUGUCUCAAAGAUUAAGCCAUGCAUGUCUAAGUAUAAGC-AAUUUAUACAGUGAAACUGCGAAUGGCUCAUUAAAUCAGUUAUCGUUUAUUUGAUAGUUC---CUUUACUACAUGGUAUAACUGUGGUAAUUCUAGAGCUAAUACAUGCUUA---------AAAUCUCGACCCUUUGGAAGAGAUGUAUUUAUUAGAUAAAAA----------------------------AUCAAUGUCUUCG------GACUCUUUGAUGAUUCAUAAUAACUU--UUCGAAUCGCAUGGCCU-UGUGCUGGCGAUGGUUCAUUCAAAUUUCUGCCCUAUCAACUUUCGAUGGUAGGAUAGUGGCCUACCAUGGUUUCAACGGGUAACGGGGAAUAAGGGUUCGAUUCCGGAGAGGGAGCCUGAGAAACGGCUACCACAUCCAAGGAAGGCAGCAGGCGCGCAAAUUACCCAAUCCUAAUUCAGGGAGGUAGUGACAAUAAAUAACGAUACAGGGCCCAUUCGGGUCU-UGUAAUUGGAAUGAGUACAAUGUAAAUACCUUAACGAGGAACAAUUGGAGGGCAAGUCUGGUGCCAGCAGCCGCGGUAAUUCCAGCUCCAAUAGCGUAUAUUAAAGUUGUUGCAGUUAAAAAGCUCGUAGUUGAACUUUGGGCCCGGUUGGCCGGUCCGAUUUUUUCGUGUACUGGAUUUCCAACGGGGCCUUUCCUUCUGGCUAACCUUGAGUCCUUGUGGCUCUUGGCGAA---------CCAGGACUUUUACUUUGAAAAAAUUAGAGUGUUCAAAGCAGGCGUAUUGC--UCGAAUAUAUUAGCAUGGAAUAAUAGAAUAGGACGUUUGGUUCUAUUUUGUUGGUUUCUAGGACCAUCGUAAUGAUUAAUAGGGACGGUCGGGGGCAUCAGUAUUCAAUUGUCAGAGGUGAAAUUCUUGGAUUUAUUGAAGACUAACUACUGCGAAAGCAUUUGCCAAGGACGUUUUCAUUAAUCAAGAACGAAAGUUAGGGGAUCGAAGAUGAUCAGAUACCGUCGUAGUCUUAACCAUAAACUAUGCCGACUAGGGAUCGGGUGGUGUUUUUUUAAUGACCCACUCGGCACCUUACGAGAAAUCAAAGUCUUUGGGUUCUGGGGGGAGUAUGGUCGCAAGGCUGAAACUUAAAGGAAUUGACGGAAGGGCACCACCAGGAGUGGAGCCUGCGGCUUAAUUUGACUCAACACGGGGAAACUCACCAGGUCCAGACACAAUAAGGAUUGACAGAUUGAGAGCUCUUUCUUGAUUUUGUGGGUGGUGGUGCAUGGCCGUUCUUAGUUGGUGGAGUGAUUUGUCUGCUUAAUUGCGAUAACGAACGAGACCUUAACCUACUAAAUAGUG--GUG-----CUAGCAUUUGCUGGUUAUCCACUUCUUAGAGGGACUAUCGGUUUCAAGCCGAUGGAAGUUUGAGGCAAUAACAGGUCUGUGAUGCCCUUAGACGUUCUGGGCCGCACGCGCGCUACACUGACGGAGCCAGCGAGUCUA-ACCUUG-GCCGAGAGGUCUUGGUAAUCUUGUGAAACUCCGUCGUGCUGGGGAUAGAGCAUUGUAAUUAUUGCUCUUCAACGAGGAAUUCCU--AGUAAGCGCAAGUCAUCAGCUUGCGUUGAUUACGUCCCUGCCCUUUGUACACACCGCCCGUCGCUAGUACCGAUUGAAUGGCUUAGUGAGGCCUCAGGAUCUGCUUAGAGAAGGGGGG-CAACUCCA---UCUCAGAGCGGAGAAUUUGGACAAACUUGGUCAUUUAGAGGAACUAAAAGUCGUAACAAGGUUUCCGUAGGUGAACCUGCGGAAGGAUCAUUA',
+      isReference: true,
+      objects: {
+        MOD_TEST: {
+          name: 'Am164_18S_Sc',
+          start: 168,
+          end: 168,
+          type: "2'-*O*-Me",
+          color: 'sky',
+          link: { name: 'modificationDetails', query: { id: 'MOD_TEST' } }
+        }
+      }
+    },
+    {
+      id: '18S_hs_Iouri_NR_0462',
+      name: 'H.sapiens - Iouri - NR_0462',
+      shortname: 'Hs-NR_0462',
+      sequence:
+        'UACCUGGUUGAUCCUGCCAGUAG-CAUAUGCUUGUCUCAAAGAUUAAGCCAUGCAUGUCUGAGUACGCACGGCCGG-UACAGUGAAACUGCGAAUGGCUCAUUAAAUCAGUUAUGGUUCCUUUGGUCGCUCGCUCCUCUCCUACUUGGAUAACUGUGGUAAUUCUAGAGCUAAUACAUGCCGACGGGCGCUGACCCCCUUCGCGGGGGGGAUGCGUGCAUUUAUCAGAUCAAAACCAACCCGGUCAGCCCCUCUCCGGCCCCGGCCGGGGGGCGGGCGCCGGCGGCUUUGGUGACUCUAGAUAACCUCGGGCCGAUCGCACGCCCCCCGUGGCGGCGACGACCCAUUCGAACGUCUGCCCUAUCAACUUUCGAUGGUAGUCGCCGUGCCUACCAUGGUGACCACGGGUGACGGGGAAUCAGGGUUCGAUUCCGGAGAGGGAGCCUGAGAAACGGCUACCACAUCCAAGGAAGGCAGCAGGCGCGCAAAUUACCCACUCCCGACCCGGGGAGGUAGUGACGAAAAAUAACAAUACAGGACUCUUUCGAGGCCCUGUAAUUGGAAUGAGUCCACUUUAAAUCCUUUAACGAGGAUCCAUUGGAGGGCAAGUCUGGUGCCAGCAGCCGCGGUAAUUCCAGCUCCAAUAGCGUAUAUUAAAGUUGCUGCAGUUAAAAAGCUCGUAGUUGGAUCUUGGGAGCGGGCGGGCGGUCCGCCGCGAGGCGAGCCACCGCCCGUCCCCGCCCCUUGCCUCUCGGCGCCCCCUCGAUGCUCUUAGCUGAGUGUCCCGCGGGGC--CCGAAGCGUUUACUUUGAAAAAAUUAGAGUGUUCAAAGCAGGCCCGAGCCGCCUGGAUACCGCAGCUAGGAAUAAUGGAAUAGGACCG-CGGUUCUAUUUUGUUGGUUUUCGGAACUGAGGCCAUGAUUAAGAGGGACGGCCGGGGGCAUUCGUAUUGCGCCGCUAGAGGUGAAAUUCUUGGACCGGCGCAAGACGGACCAGAGCGAAAGCAUUUGCCAAGAAUGUUUUCAUUAAUCAAGAACGAAAGUCGGAGGUUCGAAGACGAUCAGAUACCGUCGUAGUUCCGACCAUAAACGAUGCCGACCGGCGAUGCGGCGGCGUUAUUCCCAUGACCCGCCGGGCAGCUUCCGGGAAACCAAAGUCUUUGGGUUCCGGGGGGAGUAUGGUUGCAAAGCUGAAACUUAAAGGAAUUGACGGAAGGGCACCACCAGGAGUGGAGCCUGCGGCUUAAUUUGACUCAACACGGGAAACCUCACCCGGCCCGGACACGGACAGGAUUGACAGAUUGAUAGCUCUUUCUCGAUUCCGUGGGUGGUGGUGCAUGGCCGUUCUUAGUUGGUGGAGCGAUUUGUCUGGUUAAUUCCGAUAACGAACGAGACUCUGGCAUGCUAACUAGUUACGCGACCCCCGAGCGGUCGGCGUCCCCCAACUUCUUAGAGGGACAAGUGGCGUUCAGCCACCCGAGAUUGA--GCAAUAACAGGUCUGUGAUGCCCUUAGAUGUCCGGGGCUGCACGCGCGCUACACUGACUGGCUCAGCGUGUGCCUACCCUACGCCGGCAGGCGCGGGUAACCCGUUGAACCCCAUUCGUGAUGGGGAUCGGGGAUUGCAAUUAUUCCCCAUGAACGAGGAAUUCCC--AGUAAGUGCGGGUCAUAAGCUUGCGUUGAUUAAGUCCCUGCCCUUUGUACACACCGCCCGUCGCUACUACCGAUUGGAUGGUUUAGUGAGGCCCUCGGAUCGGCCCCGCCGGGGUCGGCCCACGGCCCUGGCGGAGCGCUGAGAAGACGGUCGAACUUGACUAUCUAGAGGAAGUAAAAGUCGUAACAAGGUUUCCGUAGGUGAACCUGCGGAAGGAUCAUUA'
+    },
+    {
+      id: '18S_Human_reference',
+      name: 'H.sapiens - ref',
+      shortname: 'Hs-Ref',
+      sequence:
+        'UACCUGGUUGAUCCUGCCAGUAG-CAUAUGCUUGUCUCAAAGAUUAAGCCAUGCAUGUCUAAGUACGCACGGCCGG-UACAGUGAAACUGCGAAUGGCUCAUUAAAUCAGUUAUGGUUCCUUUGGUCGCUCGCUCCUCUCCUACUUGGAUAACUGUGGUAAUUCUAGAGCUAAUACAUGCCGACGGGCGCUGACCCCCUUCGCGGGGGGGAUGCGUGCAUUUAUCAGAUCAAAACCAACCCGGUCAGCCCCUCUCCGGCCCCGGCCGGGGGGCGGGCGCCGGCGGCUUUGGUGACUCUAGAUAACCUCGGGCCGAUCGCACGCCCCCCGUGGCGGCGACGACCCAUUCGAACGUCUGCCCUAUCAACUUUCGAUGGUAGUCGCCGUGCCUACCAUGGUGACCACGGGUGACGGGGAAUCAGGGUUCGAUUCCGGAGAGGGAGCCUGAGAAACGGCUACCACAUCCAAGGAAGGCAGCAGGCGCGCAAAUUACCCACUCCCGACCCGGGGAGGUAGUGACGAAAAAUAACAAUACAGGACUCUUUCGAGGCCCUGUAAUUGGAAUGAGUCCACUUUAAAUCCUUUAACGAGGAUCCAUUGGAGGGCAAGUCUGGUGCCAGCAGCCGCGGUAAUUCCAGCUCCAAUAGCGUAUAUUAAAGUUGCUGCAGUUAAAAAGCUCGUAGUUGGAUCUUGGGAGCGGGCGGGCGGUCCGCCGCGAGGCGAGCCACCGCCCGUCCCCGCCCCUUGCCUCUCGGCGCCCCCUCGAUGCUCUUAGCUGAGUGUCCCGCGGGGC--CCGAAGCGUUUACUUUGAAAAAAUUAGAGUGUUCAAAGCAGGCCCGAGCCGCCUGGAUACCGCAGCUAGGAAUAAUGGAAUAGGACCG-CGGUUCUAUUUUGUUGGUUUUCGGAACUGAGGCCAUGAUUAAGAGGGACGGCCGGGGGCAUUCGUAUUGCGCCGCUAGAGGUGAAAUUCUUGGACCGGCGCAAGACGGACCAGAGCGAAAGCAUUUGCCAAGAAUGUUUUCAUUAAUCAAGAACGAAAGUCGGAGGUUCGAAGACGAUCAGAUACCGUCGUAGUUCCGACCAUAAACGAUGCCGACCGGCGAUGCGGCGGCGUUAUUCCCAUGACCCGCCGGGCAGCUUCCGGGAAACCAAAGUCUUUGGGUUCCGGGGGGAGUAUGGUUGCAAAGCUGAAACUUAAAGGAAUUGACGGAAGGGCACCACCAGGAGUGGAGCCUGCGGCUUAAUUUGACUCAACACGGGAAACCUCACCCGGCCCGGACACGGACAGGAUUGACAGAUUGAUAGCUCUUUCUCGAUUCCGUGGGUGGUGGUGCAUGGCCGUUCUUAGUUGGUGGAGCGAUUUGUCUGGUUAAUUCCGAUAACGAACGAGACUCUGGCAUGCUAACUAGUUACGCGACCCCCGAGCGGUCGGCGUCCCCCAACUUCUUAGAGGGACAAGUGGCGUUCAGCCACCCGAGAUUGA--GCAAUAACAGGUCUGUGAUGCCCUUAGAUGUCCGGGGCUGCACGCGCGCUACACUGACUGGCUCAGCGUGUGCCUACCCUACGCCGGCAGGCGCGGGUAACCCGUUGAACCCCAUUCGUGAUGGGGAUCGGGGAUUGCAAUUAUUCCCCAUGAACGAGGGAAUUCCCGAGUAAGUGCGGGUCAUAAGCUUGCGUUGAUUAAGUCCCUGCCCUUUGUACACACCGCCCGUCGCUACUACCGAUUGGAUGGUUUAGUGAGGCCCUCGGAUCGGCCCCGCCGGGGUCGGCCCACGGCCCUGGCGGAGCGCUGAGAAGACGGUCGAACUUGACUAUCUAGAGGAAGUAAAAGUCGUAACAAGGUUUCCGUAGGUGAACCUGCGGAAGGAUCAUUA'
+    }
+  ]
+}
+
+/**
+ * Component props.
+ */
+const props = defineProps<{
+  /** The mode in which the alignment form is at landing (usually passed
+   * from URL). */
+  initialMode: AlignmentModesType
+}>()
+
+/**
+ * Vue Router instance reactive object.
+ */
+const router = useRouter()
+
+/**
+ * The currently selected mode.
+ */
+const activeMode = ref(props.initialMode)
+
+/**
+ * Title of the page, reactively updated when data is fetched.
+ */
+const pageTitle = computed(
+  () => `${_capitalize(activeMode.value)} • Alignment | SnoBoard`
+)
+// Bind actual page title to computed one
+onMounted(() => useTitle(pageTitle))
+
+/**
+ * Callback to change the URL when switching tab.
+ * @param e The event emitted when changing tab.
+ */
+const updateUrlQuery = (newMode: AlignmentModesType) => {
+  if (newMode) {
+    router.replace({
+      name: 'alignment',
+      query: { mode: newMode }
+    })
+  }
+}
+
+/**
+ * The IDs of currently selected sequences.
+ */
+const selectedSequenceIds = ref<string[]>([])
+</script>
+
+<template>
+  <MainLayout padded>
+    <h1 class="mb-8 text-center text-3xl font-semibold text-slate-700">
+      <icon-snoboard-alignment class="mb-1 mr-2 inline" />
+      Sequences alignment
+    </h1>
+
+    <AlignmentForm
+      v-model:current-mode-model="activeMode"
+      v-model:selected-ids-model="selectedSequenceIds"
+      class="mb-8"
+      @update:current-mode-model="updateUrlQuery"
+    />
+
+    <div class="my-8">
+      <SequenceAlignment :alignment="ALIGNMENT" />
+    </div>
+  </MainLayout>
+</template>
diff --git a/src/views/ClusterView.vue b/src/views/ClusterView.vue
index 769549f121408f4d998e8c48c0bcd030c1d7dce8..a0bee4e2b1f2df59ad2b7b7e823a0d8a8518a097 100644
--- a/src/views/ClusterView.vue
+++ b/src/views/ClusterView.vue
@@ -16,11 +16,14 @@ import IconFa6SolidArrowUpRightFromSquare from '~icons/fa6-solid/arrow-up-right-
 import IconFa6SolidList from '~icons/fa6-solid/list'
 import IconEmojioneThinkingFace from '~icons/emojione/thinking-face'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
-import { omit as _omit, minBy as _minBy, maxBy as _maxBy } from 'lodash-es'
 import { useQuery } from '@urql/vue'
 import { useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
+import { omit as _omit, minBy as _minBy, maxBy as _maxBy } from 'lodash-es'
 /**
  * Types imports
  */
diff --git a/src/views/DataTableView.vue b/src/views/DataTableView.vue
index 235f9d03773e359d834159ddb0e4a8ff858aa7f7..acbaaac7cde290d3459849b59e20217a422ad269 100644
--- a/src/views/DataTableView.vue
+++ b/src/views/DataTableView.vue
@@ -25,6 +25,10 @@ import IconFa6SolidCircleQuestion from '~icons/fa6-solid/circle-question'
 import IconFa6SolidCircleXmark from '~icons/fa6-solid/circle-xmark'
 import IconFa6SolidFilter from '~icons/fa6-solid/filter'
 import IconSnoboardFilterWarning from '~icons/snoboard/filter-warning'
+/**
+ * Composables imports
+ */
+import { useQuery } from '@urql/vue'
 /**
  * Other 3rd-party imports
  */
@@ -36,7 +40,6 @@ import {
   findLast as _findLast
 } from 'lodash-es'
 import { FilterMatchMode as primeVueFilterMatchMode } from 'primevue/api'
-import { useQuery } from '@urql/vue'
 /**
  * Types imports
  */
@@ -265,46 +268,36 @@ const targetNameOptionsBase = computed(() =>
 /**
  * Available options for target name selection, grouped.
  */
-const targetNameOptionsWithDisablingGroups = computed(() =>
+const targetNameOptionGroups = computed(() =>
   targetNameOptionsBase.value.reduce<
     { label: string; children: { label: string; value: any }[] }[]
-  >((targetNameOptionsWithDisablingGroups, targetNameOption) => {
+  >((targetNameOptionGroups, targetNameOption) => {
     // Get index of the group of the current option
-    const targetNameOptionGroupIndex =
-      targetNameOptionsWithDisablingGroups.findIndex(
-        (group) => group.label === targetNameOption.groupLabel
-      )
+    const targetNameOptionGroupIndex = targetNameOptionGroups.findIndex(
+      (group) => group.label === targetNameOption.groupLabel
+    )
     // Insert option in existing group if present
     // Using non-null type assertion for
-    // `targetNameOptionsWithDisablingGroups[targetNameOptionGroupIndex]`
+    // `targetNameOptionGroups[targetNameOptionGroupIndex]`
     // because it is checked before
     return targetNameOptionGroupIndex !== -1
       ? [
-          ...targetNameOptionsWithDisablingGroups.slice(
-            0,
-            targetNameOptionGroupIndex
-          ),
+          ...targetNameOptionGroups.slice(0, targetNameOptionGroupIndex),
           {
-            label:
-              targetNameOptionsWithDisablingGroups[targetNameOptionGroupIndex]!
-                .label,
+            label: targetNameOptionGroups[targetNameOptionGroupIndex]!.label,
             children: [
-              ...targetNameOptionsWithDisablingGroups[
-                targetNameOptionGroupIndex
-              ]!.children,
+              ...targetNameOptionGroups[targetNameOptionGroupIndex]!.children,
               {
                 label: targetNameOption.label || '',
                 value: targetNameOption.value
               }
             ]
           },
-          ...targetNameOptionsWithDisablingGroups.slice(
-            targetNameOptionGroupIndex + 1
-          )
+          ...targetNameOptionGroups.slice(targetNameOptionGroupIndex + 1)
         ]
       : // Otherwise add the group with the option
         [
-          ...targetNameOptionsWithDisablingGroups,
+          ...targetNameOptionGroups,
           {
             label: targetNameOption.groupLabel,
             children: [
@@ -733,7 +726,7 @@ const specificFilterConfigs = computed<{
       columns.find((column) => column.id == 'targetName')?.field || '',
     filter: {
       matchMode: primeVueFilterMatchMode.IN,
-      options: targetNameOptionsWithDisablingGroups.value
+      options: targetNameOptionGroups.value
     },
     grouped: true
   },
diff --git a/src/views/GuideView.vue b/src/views/GuideView.vue
index 004dc3bc91150dd534becb3b66af2fceef5536f5..d518217bdfabf68a820f773b15c85e08684e8556 100644
--- a/src/views/GuideView.vue
+++ b/src/views/GuideView.vue
@@ -26,17 +26,20 @@ import IconFa6SolidCirclePlus from '~icons/fa6-solid/circle-plus'
 import IconFa6SolidCircleQuestion from '~icons/fa6-solid/circle-question'
 import IconFa6SolidCircleXmark from '~icons/fa6-solid/circle-xmark'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
-import { uniq as _uniq } from 'lodash-es'
 import { useQuery } from '@urql/vue'
 import { useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
+import { uniq as _uniq } from 'lodash-es'
 /**
  * Types import
  */
 import type { TailwindDefaultColorNameModel } from '@/typings/styleTypes'
 import type { InteractionCardModel } from '@/components/InteractionCard.vue'
-import type { highlightGroupModel } from '@/components/SequenceBoard.vue'
+import type { objectModel } from '@/components/SequenceBoard.vue'
 import {
   GraphQlType,
   ModifType,
@@ -269,7 +272,7 @@ const filteredFacingModifications = computed(() =>
  */
 const sequenceChunks = computed(() => ({
   ...guide.value?.boxConnections.edges.reduce<{
-    [groupId: string]: highlightGroupModel
+    [groupId: string]: objectModel
   }>((boxes, boxConnection) => {
     return boxConnection.node.annotation
       ? {
@@ -288,7 +291,7 @@ const sequenceChunks = computed(() => ({
       : boxes
   }, {}),
   ...filteredFacingModifications.value?.reduce<{
-    [groupId: string]: highlightGroupModel
+    [groupId: string]: objectModel
   }>(
     (sequenceChunks, facingModification) => ({
       ...sequenceChunks,
@@ -789,7 +792,7 @@ const selectedGraphicsTab = ref(GraphicsTabEnum[props.initialGraphicsPanelTab])
         v-if="guide?.seq"
         :sequence="guide.seq.replace(/T/g, 'U')"
         :sequence-id="guide.id"
-        :highlighted-groups="sequenceChunks"
+        :objects="sequenceChunks"
         :legend-items="GUIDE_LEGEND_ITEMS"
       >
         <template #legend-item-title="{ item }">
@@ -802,7 +805,7 @@ const selectedGraphicsTab = ref(GraphicsTabEnum[props.initialGraphicsPanelTab])
           </span>
         </template>
 
-        <template #tooltip-item="{ group }">
+        <template #tooltip-item="{ object: group }">
           <Chip
             v-if="group.type && isInEnum(group.type, ModifType)"
             :class="[
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 4097e8afbf6145dfaa55ed1a0350fe6933ea8b45..65e5b081470b069e103e86ee35f6f9042a54b507 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -3,7 +3,6 @@
  * Vue imports
  */
 import { computed, ref } from 'vue'
-import { useRouter } from 'vue-router'
 /**
  * Components imports
  */
@@ -28,9 +27,13 @@ import IconTablerCircleArrowDownFilled from '~icons/tabler/circle-arrow-down-fil
 import IconSnoboardGuide from '~icons/snoboard/guide'
 import IconSnoboardModification from '~icons/snoboard/modification'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
+import { useRouter } from 'vue-router'
+/**
+ * Other 3rd-party imports
+ */
 import { uniqWith as _uniqWith, isEqual as _isEqual } from 'lodash-es'
 /**
  * Types imports.
@@ -302,39 +305,39 @@ const menuItems = computed<MenuItem[]>(() => [
     key: 'conservation',
     label: 'Conservation',
     items: [
-      {
-        key: 'conservationModifications',
-        label: 'Modifications',
-        route: {
-          // name: 'conservation',
-          // query: {
-          //   type: 'modification'
-          // }
-        },
-        iconComponent: IconSnoboardModification,
-        disabled: true
-      },
+      // {
+      //   key: 'conservationModifications',
+      //   label: 'Modifications',
+      //   route: {
+      //     name: 'alignment'
+      //     // query: {
+      //     //   type: 'modification'
+      //     // }
+      //   },
+      //   iconComponent: IconSnoboardModification,
+      //   disabled: true
+      // },
       {
         key: 'conservationGuides',
         label: 'Guides',
-        route: {
-          // name: 'conservation',
-          // query: {
-          //   type: 'modification'
-          // }
-        },
+        // route: {
+        //   name: 'alignment',
+        //   query: {
+        //     mode: 'guide'
+        //   }
+        // },
         iconComponent: IconSnoboardGuide,
         disabled: true
       },
       {
         key: 'conservationTargets',
         label: 'Targets',
-        route: {
-          // name: 'conservation',
-          // query: {
-          //   type: 'modification'
-          // }
-        },
+        // route: {
+        //   name: 'alignment',
+        //   query: {
+        //     mode: 'target'
+        //   }
+        // },
         iconComponent: IconFa6SolidBullseye,
         disabled: true
       }
diff --git a/src/views/LegalView.vue b/src/views/LegalView.vue
index 03dc9222ea51160ba7ae273db20b5f656b0a6def..b0b28e258d3759391f5c12c4dd29c81027473359 100644
--- a/src/views/LegalView.vue
+++ b/src/views/LegalView.vue
@@ -9,7 +9,7 @@ import { computed, toRef } from 'vue'
 import MainLayout from '@/layouts/MainLayout.vue'
 import BaseRenderedMarkdown from '@/components/BaseRenderedMarkdown.vue'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
 /**
diff --git a/src/views/ModificationView.vue b/src/views/ModificationView.vue
index db242e8a601882df0f82378480acb12048df1862..ff226c126b3c5ad16787c5af3f68c7eb58d93237 100644
--- a/src/views/ModificationView.vue
+++ b/src/views/ModificationView.vue
@@ -18,10 +18,13 @@ import Tag from 'primevue/tag'
 import IconFa6SolidCircleInfo from '~icons/fa6-solid/circle-info'
 import IconFa6SolidDrawPolygon from '~icons/fa6-solid/draw-polygon'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
 import { useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
 import { sortBy as _sortBy } from 'lodash-es'
 /**
  * Types imports
diff --git a/src/views/OrganismView.vue b/src/views/OrganismView.vue
index 19b000064e708a9068ecdd61b5bb30adb513137f..3379ae7e0bb87928172583f08f2ad8bf12a74306 100644
--- a/src/views/OrganismView.vue
+++ b/src/views/OrganismView.vue
@@ -25,10 +25,13 @@ import IconFa6SolidFileLines from '~icons/fa6-solid/file-lines'
 import IconCarbonAccessibilityColor from '~icons/carbon/accessibility-color'
 import IconCarbonAccessibilityColorFilled from '~icons/carbon/accessibility-color-filled'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
 import { useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
 import {
   sortBy as _sortBy,
   capitalize as _capitalize,
diff --git a/src/views/SelectionView.vue b/src/views/SelectionView.vue
index b6b100ac642f78a99f519fbfcd93d8f3485add9e..cf4fd8e6607ebbc3c2cf00cd2fccb18370d86d7f 100644
--- a/src/views/SelectionView.vue
+++ b/src/views/SelectionView.vue
@@ -3,48 +3,39 @@
  * Vue imports
  */
 import { computed, onMounted, ref } from 'vue'
-import { useRouter } from 'vue-router'
 /**
  * Components imports
  */
 import MainLayout from '@/layouts/MainLayout.vue'
-import ModificationSelectionForm, {
-  type ModificationSelectionModel
-} from '@/components/ModificationSelectionForm.vue'
-import GuideSelectionForm, {
-  type GuideSelectionModel
-} from '@/components/GuideSelectionForm.vue'
-import TargetSelectionForm, {
-  type TargetSelectionModel
-} from '@/components/TargetSelectionForm.vue'
-import TabView, { type TabViewChangeEvent } from 'primevue/tabview'
-import TabPanel from 'primevue/tabpanel'
-import Card from 'primevue/card'
+import SelectionForm from '@/components/SelectionForm.vue'
 import Button from 'primevue/button'
+import IconFa6SolidSliders from '~icons/fa6-solid/sliders'
 import IconFa6SolidTable from '~icons/fa6-solid/table'
 import IconFa6SolidBullseye from '~icons/fa6-solid/bullseye'
 import IconFa6SolidCircleNodes from '~icons/fa6-solid/circle-nodes'
 import IconSnoboardSequence from '~icons/snoboard/sequence'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
+import { useRouter } from 'vue-router'
 import { useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
 import { capitalize as _capitalize } from 'lodash-es'
+/**
+ * Types imports
+ */
+import type { SelectionModel } from '@/components/SelectionForm.vue'
 /**
  * Utils imports
  */
-import { SELECTION_FORM_MODES } from '@/utils/constant'
-import { getColorWithOptionalShade } from '@/utils/colors'
+import { SELECTION_MODES } from '@/utils/constant'
 
 /**
  * Type of data to select.
  */
-export type SelectionFormModesType = (typeof SELECTION_FORM_MODES)[number]
-enum TabEnum {
-  Modification = 0,
-  Guide,
-  Target
-}
+export type SelectionModesType = (typeof SELECTION_MODES)[number]
 
 /**
  * A selection option.
@@ -99,7 +90,9 @@ const TABLE_COLUMNS_BY_MODE = {
  * Component props.
  */
 const props = defineProps<{
-  mode: SelectionFormModesType
+  /** The mode in which the selection form is at landing (usually passed
+   * from URL). */
+  initialMode: SelectionModesType
 }>()
 
 /**
@@ -108,16 +101,9 @@ const props = defineProps<{
 const router = useRouter()
 
 /**
- * The index of the tab currently selected, reactively updated when changed.
- */
-const activeTabIndex = ref<TabEnum>(
-  SELECTION_FORM_MODES.findIndex((mode) => mode === props.mode)
-)
-
-/**
- * The mode corresponding to the tab currently selected.
+ * The currently selected mode.
  */
-const activeMode = computed(() => SELECTION_FORM_MODES[activeTabIndex.value])
+const activeMode = ref(props.initialMode)
 
 /**
  * Title of the page, reactively updated when data is fetched.
@@ -132,21 +118,19 @@ onMounted(() => useTitle(pageTitle))
  * Callback to change the URL when switching tab.
  * @param e The event emitted when changing tab.
  */
-const updateUrlQuery = (e: TabViewChangeEvent) => {
-  const newMode = SELECTION_FORM_MODES[e.index]
+const updateUrlQuery = (newMode: SelectionModesType) => {
   if (newMode) {
-    router.replace({ name: 'selection', query: { mode: newMode } })
+    router.replace({
+      name: 'selection',
+      query: { mode: newMode }
+    })
   }
 }
 
 /**
  * The current selection.
  */
-const selection = ref<{
-  modification?: ModificationSelectionModel
-  guide?: GuideSelectionModel
-  target?: TargetSelectionModel
-}>({
+const selection = ref<SelectionModel>({
   modification: undefined,
   guide: undefined,
   target: undefined
@@ -159,7 +143,7 @@ const selection = ref<{
 const tableFilters = computed(() => ({
   guideSubclass:
     activeMode.value === 'guide'
-      ? selection.value[activeMode.value]?.guideSubclasses
+      ? selection.value.guide?.guideSubclassLabels
       : undefined,
   targetName: selection.value[activeMode.value]?.targetNames,
   modificationType: selection.value[activeMode.value]?.modificationTypes,
@@ -191,152 +175,105 @@ const onlyTargetIdActiveMode = computed(() =>
 
 <template>
   <MainLayout padded>
-    <h1 class="text-center text-3xl font-semibold text-slate-700">
+    <h1 class="mb-8 text-center text-3xl font-semibold text-slate-700">
+      <icon-fa6-solid-sliders class="mb-1 mr-2 inline" />
       Advanced selection
     </h1>
 
-    <Card
-      class="mx-16 !rounded-2xl border-none !shadow-none"
-      :pt="{
-        footer: {
-          style: {
-            display: 'flex',
-            justifyContent: 'center'
+    <SelectionForm
+      v-model:current-mode-model="activeMode"
+      v-model:selection-model="selection"
+      v-model:only-target-id-by-mode-model="onlyTargetIdByMode"
+      @update:current-mode-model="updateUrlQuery"
+    />
+
+    <div class="mt-8 flex justify-center gap-4">
+      <RouterLink
+        :to="{
+          name: 'table',
+          query: {
+            columns: TABLE_COLUMNS_BY_MODE[activeMode],
+            ...tableFilters
           }
-        }
-      }"
-    >
-      <template #content>
-        <TabView
-          v-model:active-index="activeTabIndex"
-          :pt="{
-            nav: {
-              style: {
-                justifyContent: 'center',
-                marginBottom: '2rem',
-                fontSize: '1.25em',
-                background: `linear-gradient(white 0 0) padding-box,
-                linear-gradient(90deg,
-                  ${getColorWithOptionalShade('slate', '300')}00 10%,
-                  ${getColorWithOptionalShade('slate', '300')}   15%,
-                  ${getColorWithOptionalShade('slate', '300')}   85%,
-                  ${getColorWithOptionalShade('slate', '300')}00 90%)
-                border-box`,
-                borderStyle: 'dashed',
-                borderColor: 'white'
+        }"
+      >
+        <Button>
+          <icon-fa6-solid-table />
+          <span class="ml-2">View in table</span>
+        </Button>
+      </RouterLink>
+
+      <div
+        v-if="activeMode === 'target'"
+        v-tooltip.top="
+          !onlyTargetIdByMode.target && {
+            value: 'Select a unique target/species pair',
+            pt: {
+              text: {
+                style: {
+                  textAlign: 'center',
+                  fontStyle: 'italic'
+                }
               }
             }
+          }
+        "
+      >
+        <RouterLink
+          :to="{
+            name: 'targetDetails',
+            query: {
+              id: onlyTargetIdByMode.target
+            },
+            hash: '#sequence-panel'
           }"
-          @tab-change="updateUrlQuery"
+          :class="{ 'pointer-events-none': !onlyTargetIdByMode.target }"
         >
-          <TabPanel header="Modification">
-            <ModificationSelectionForm
-              v-model:selection-model="selection.modification"
-              v-model:only-target-id="onlyTargetIdByMode.modification"
-            />
-          </TabPanel>
-          <TabPanel header="Guide">
-            <GuideSelectionForm v-model:selection-model="selection.guide" />
-          </TabPanel>
-          <TabPanel header="Target">
-            <TargetSelectionForm
-              v-model:selection-model="selection.target"
-              v-model:only-target-id="onlyTargetIdByMode.target"
-            />
-          </TabPanel>
-        </TabView>
-      </template>
+          <Button :disabled="!onlyTargetIdByMode.target">
+            <icon-snoboard-sequence />
+            <span class="ml-2">View sequence</span>
+          </Button>
+        </RouterLink>
+      </div>
 
-      <template #footer>
-        <div class="flex gap-4">
-          <RouterLink
-            :to="{
-              name: 'table',
-              query: {
-                columns: TABLE_COLUMNS_BY_MODE[activeMode],
-                ...tableFilters
-              }
-            }"
-          >
-            <Button>
-              <icon-fa6-solid-table />
-              <span class="ml-2">View in table</span>
-            </Button>
-          </RouterLink>
-
-          <div
-            v-if="activeMode === 'target'"
-            v-tooltip.top="
-              !onlyTargetIdByMode.target && {
-                value: 'Select a unique target/species pair',
-                pt: {
-                  text: {
-                    style: {
-                      textAlign: 'center',
-                      fontStyle: 'italic'
-                    }
-                  }
+      <div
+        v-if="activeMode === 'target' || activeMode === 'modification'"
+        v-tooltip.top="
+          !onlyTargetIdActiveMode && {
+            value: 'Select a unique target/species pair',
+            pt: {
+              text: {
+                style: {
+                  textAlign: 'center',
+                  fontStyle: 'italic'
                 }
               }
-            "
-          >
-            <RouterLink
-              :to="{
-                name: 'targetDetails',
-                query: {
-                  id: onlyTargetIdByMode.target
-                },
-                hash: '#sequence-panel'
-              }"
-              :class="{ 'pointer-events-none': !onlyTargetIdByMode.target }"
-            >
-              <Button :disabled="!onlyTargetIdByMode.target">
-                <icon-snoboard-sequence />
-                <span class="ml-2">View sequence</span>
-              </Button>
-            </RouterLink>
-          </div>
-
-          <div
-            v-if="activeMode === 'target' || activeMode === 'modification'"
-            v-tooltip.top="
-              !onlyTargetIdActiveMode && {
-                value: 'Select a unique target/species pair',
-                pt: {
-                  text: {
-                    style: {
-                      textAlign: 'center',
-                      fontStyle: 'italic'
-                    }
-                  }
-                }
-              }
-            "
-          >
-            <RouterLink
-              :to="{
-                name: 'targetDetails',
-                query: {
-                  id: onlyTargetIdActiveMode,
-                  graphicsTab: '2d-struct'
-                },
-                hash: '#graphics-panel'
-              }"
-              :class="{ 'pointer-events-none': !onlyTargetIdActiveMode }"
-            >
-              <Button :disabled="!onlyTargetIdActiveMode">
-                <icon-fa6-solid-bullseye v-if="activeMode === 'modification'" />
-                <icon-fa6-solid-circle-nodes v-else />
-                <span class="ml-2">
-                  View
-                  {{ activeMode === 'modification' ? 'on target' : '' }}
-                  structure
-                </span>
-              </Button>
-            </RouterLink>
-          </div>
-        </div>
-      </template>
-    </Card>
+            }
+          }
+        "
+      >
+        <RouterLink
+          :to="{
+            name: 'targetDetails',
+            query: {
+              id: onlyTargetIdActiveMode,
+              graphicsTab: '2d-struct'
+            },
+            hash: '#graphics-panel'
+          }"
+          :class="{ 'pointer-events-none': !onlyTargetIdActiveMode }"
+        >
+          <Button :disabled="!onlyTargetIdActiveMode">
+            <icon-fa6-solid-bullseye v-if="activeMode === 'modification'" />
+            <icon-fa6-solid-circle-nodes v-else />
+            <span class="ml-2">
+              View
+              {{ activeMode === 'modification' ? 'on target' : '' }}
+              structure
+            </span>
+          </Button>
+        </RouterLink>
+      </div>
+    </div>
   </MainLayout>
 </template>
diff --git a/src/views/StatisticsView.vue b/src/views/StatisticsView.vue
index 9729c7818eccb53e49cf6d35c2c67d0ad6b89293..e2459d6fcece7382dc3341ccc00eb976c8b938b9 100644
--- a/src/views/StatisticsView.vue
+++ b/src/views/StatisticsView.vue
@@ -17,9 +17,12 @@ import IconCarbonAccessibilityColorFilled from '~icons/carbon/accessibility-colo
 import IconSnoboardModification from '~icons/snoboard/modification'
 import IconSnoboardGuide from '~icons/snoboard/guide'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
 import { useQuery } from '@urql/vue'
+/**
+ * Other 3rd-party imports
+ */
 import { countBy as _countBy } from 'lodash-es'
 import pattern from 'patternomaly'
 /**
diff --git a/src/views/TargetView.vue b/src/views/TargetView.vue
index b9bf64cd3581accc925443b57b8c9bd5a2c86933..6c48a2fe5f3a559ffe67b8f0cc6531ebc9c2504f 100644
--- a/src/views/TargetView.vue
+++ b/src/views/TargetView.vue
@@ -28,18 +28,25 @@ import IconFa6SolidCirclePlus from '~icons/fa6-solid/circle-plus'
 import IconFa6SolidCircleQuestion from '~icons/fa6-solid/circle-question'
 import IconFa6SolidCircleXmark from '~icons/fa6-solid/circle-xmark'
 /**
- * Other 3rd-party imports
+ * Composables imports
  */
-import { find as _find, sortBy as _sortBy } from 'lodash-es'
 import { useQuery } from '@urql/vue'
 import { useFetch, useTitle } from '@vueuse/core'
+/**
+ * Other 3rd-party imports
+ */
+import {
+  find as _find,
+  sortBy as _sortBy,
+  mapValues as _mapValues
+} from 'lodash-es'
 /**
  * Types import
  */
 import type { TailwindDefaultColorNameModel } from '@/typings/styleTypes'
 import type { InteractionCardModel } from '@/components/InteractionCard.vue'
-import type { C4GGraphModel, C4GNodeModel } from '@/typings/Codev4GraphFormat'
-import type { highlightGroupModel } from '@/components/SequenceBoard.vue'
+import type { C4GGraphModel } from '@/typings/Codev4GraphFormat'
+import type { objectModel } from '@/components/SequenceBoard.vue'
 import {
   GraphQlType,
   ModifType,
@@ -173,37 +180,28 @@ const secondaryStructureWithModificationsMetadata =
       secondaryStructure.value && {
         graph: {
           ...secondaryStructure.value?.graph,
-          nodes: Object.entries(
-            secondaryStructure.value?.graph.nodes || {}
-          ).reduce<{ [nodeId: string]: C4GNodeModel }>(
-            (nodes, [nodeId, node]) => {
-              const nodeModification = _find(target.value?.modifications, [
-                'position',
-                _find(node.metadata?.data, ['label', 'nucleotidePosition'])
-                  ?.value
-              ])
-              return nodeModification
-                ? {
-                    ...nodes,
-                    [`${nodeId}`]: {
-                      ...node,
-                      metadata: {
-                        ...node.metadata,
-                        data: [
-                          ...(node.metadata?.data || []),
-                          {
-                            label: 'modification',
-                            type: 'number',
-                            value: nodeModification
-                          }
-                        ]
+          nodes: _mapValues(secondaryStructure.value?.graph.nodes, (node) => {
+            const nodeModification = _find(target.value?.modifications, [
+              'position',
+              _find(node.metadata?.data, ['label', 'nucleotidePosition'])?.value
+            ])
+            return nodeModification
+              ? {
+                  ...node,
+                  metadata: {
+                    ...node.metadata,
+                    data: [
+                      ...(node.metadata?.data || []),
+                      {
+                        label: 'modification',
+                        type: 'number',
+                        value: nodeModification
                       }
-                    }
+                    ]
                   }
-                : { ...nodes, [`${nodeId}`]: node }
-            },
-            {}
-          )
+                }
+              : node
+          })
         }
       }
   )
@@ -313,7 +311,7 @@ const filteredModifications = computed(
  */
 const sequenceChunks = computed(() =>
   filteredModifications.value.reduce<{
-    [groupId: string]: highlightGroupModel
+    [groupId: string]: objectModel
   }>(
     (sequenceChunks, modification) => ({
       ...sequenceChunks,
@@ -698,7 +696,7 @@ const selectedGraphicsTab = ref(GraphicsTabEnum[props.initialGraphicsPanelTab])
         v-if="target?.seq"
         :sequence="target.seq.replace(/T/g, 'U')"
         :sequence-id="target.id"
-        :highlighted-groups="sequenceChunks"
+        :objects="sequenceChunks"
         :legend-items="TARGET_LEGEND_ITEMS"
       >
         <template #legend-item-title="{ item }">
@@ -710,7 +708,7 @@ const selectedGraphicsTab = ref(GraphicsTabEnum[props.initialGraphicsPanelTab])
           />
         </template>
 
-        <template #tooltip-item="{ group }">
+        <template #tooltip-item="{ object: group }">
           <Chip
             v-if="group.type && isInEnum(group.type, ModifType)"
             :class="[
diff --git a/tailwind.config.js b/tailwind.config.js
index 0b7312ea8f7f42178c407698151f0f38fc73ec3a..80e2887f6afbd23c8c3a1c4c5e31e0870390afa0 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -53,6 +53,8 @@ export default {
       pattern: /^stroke-[a-z]+-600$/
     },
     'brightness-90', // ChromosomeMagnify
-    'cursor-pointer' // ChromosomeMagnify
+    'cursor-pointer', // ChromosomeMagnify
+    'text-xs', // SecondaryStructure, SequenceAlignment (tooltip)
+    'text-center' // SecondaryStructure, SequenceAlignment (tooltip)
   ]
 }