diff --git a/packages/common/src/fixtures/rank/1-rank.xml b/packages/common/src/fixtures/rank/1-rank.xml
index ceacbbedd..935d715cc 100644
--- a/packages/common/src/fixtures/rank/1-rank.xml
+++ b/packages/common/src/fixtures/rank/1-rank.xml
@@ -1 +1 @@
-RankHealthFamily and FriendsCareer Growth and Learning OpportunitiesFinancial StabilityPursuit of Hobbies and PassionsEnvironmental SustainabilityTime Management and Work-Life BalanceBuilding a Supportive CommunityPersonal Development and MindfulnessCreativity and InnovationWhat values guide your decision-making?SantéFamille et amisCroissance professionnelle et opportunités d'apprentissageStabilité financièrePoursuite de loisirs et passionsDurabilité environnementaleGestion du temps et équilibre vie professionnelle/vie personnelleConstruire une communauté solidaireDéveloppement personnel et pleine conscienceCréativité et innovationQuelles valeurs guident votre prise de décision?decision_making-0healthdecision_making-1family_and_friendsdecision_making-2career_growth_and_learning_opportunitiesdecision_making-3financial_stabilitydecision_making-4pursuit_of_hobbies_and_passionsdecision_making-5environmental_sustainabilitydecision_making-6time_management_and_work_life_balancedecision_making-7building_a_supportive_communitydecision_making-8personal_development_and_mindfulnessdecision_making-9creativity_and_innovation
\ No newline at end of file
+RankHealthFamily and FriendsCareer Growth and Learning OpportunitiesFinancial StabilityPursuit of Hobbies and PassionsEnvironmental SustainabilityTime Management and Work-Life BalanceBuilding a Supportive CommunityPersonal Development and MindfulnessCreativity and InnovationWhat values guide your decision-making?SantéFamille et amisCroissance professionnelle et opportunités d'apprentissageStabilité financièrePoursuite de loisirs et passionsDurabilité environnementaleGestion du temps et équilibre vie professionnelle/vie personnelleConstruire une communauté solidaireDéveloppement personnel et pleine conscienceCréativité et innovationQuelles valeurs guident votre prise de décision?decision_making-0healthdecision_making-1family_and_friendsdecision_making-2career_growth_and_learning_opportunitiesdecision_making-3financial_stabilitydecision_making-4pursuit_of_hobbies_and_passionsdecision_making-5environmental_sustainabilitydecision_making-6time_management_and_work_life_balancedecision_making-7building_a_supportive_communitydecision_making-8personal_development_and_mindfulnessdecision_making-9creativity_and_innovation
diff --git a/packages/web-forms/src/components/FormQuestion.vue b/packages/web-forms/src/components/FormQuestion.vue
index fd5e89fda..21cd00d99 100644
--- a/packages/web-forms/src/components/FormQuestion.vue
+++ b/packages/web-forms/src/components/FormQuestion.vue
@@ -4,6 +4,7 @@ import type {
AnyInputNode,
AnyUnsupportedControlNode,
NoteNode,
+ RankNode,
SelectNode,
} from '@getodk/xforms-engine';
import { inject } from 'vue';
@@ -12,6 +13,7 @@ import NoteControl from './controls/NoteControl.vue';
import SelectControl from './controls/SelectControl.vue';
import TriggerControl from './controls/TriggerControl.vue';
import UnsupportedControl from './controls/UnsupportedControl.vue';
+import RankControl from '@/components/controls/RankControl.vue';
type ControlNode = AnyControlNode | AnyUnsupportedControlNode;
@@ -19,6 +21,7 @@ defineProps<{ question: ControlNode }>();
const isInputNode = (n: ControlNode): n is AnyInputNode => n.nodeType === 'input';
const isSelectNode = (n: ControlNode): n is SelectNode => n.nodeType === 'select';
+const isRankNode = (n: ControlNode): n is RankNode => n.nodeType === 'rank';
const isNoteNode = (n: ControlNode): n is NoteNode => n.nodeType === 'note';
const isTriggerNode = (node: ControlNode) => node.nodeType === 'trigger';
@@ -37,6 +40,8 @@ const submitPressed = inject('submitPressed');
+
+
diff --git a/packages/web-forms/src/components/controls/RankControl.vue b/packages/web-forms/src/components/controls/RankControl.vue
new file mode 100644
index 000000000..5c01ed95f
--- /dev/null
+++ b/packages/web-forms/src/components/controls/RankControl.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
{{ "Hi rank!" }}
+
+
+
diff --git a/packages/xforms-engine/src/client/RankNode.ts b/packages/xforms-engine/src/client/RankNode.ts
new file mode 100644
index 000000000..e6842aeff
--- /dev/null
+++ b/packages/xforms-engine/src/client/RankNode.ts
@@ -0,0 +1,20 @@
+import type { InputValue } from './InputNode.ts';
+import type { ValueType } from './ValueType.ts';
+import type { LeafNodeDefinition } from '../parse/model/LeafNodeDefinition.ts';
+import { RankControlDefinition } from '../parse/body/control/RankControlDefinition.ts';
+import type { BaseValueNode } from './BaseValueNode.ts';
+
+export type RankItemValue = NonNullable>;
+
+export type RankValues = ReadonlyArray>;
+
+export interface RankDefinition extends LeafNodeDefinition {
+ readonly bodyElement: RankControlDefinition;
+}
+
+export interface RankNode extends BaseValueNode> {
+ readonly nodeType: 'rank';
+}
+
+// prettier-ignore
+export type AnyRankNode = RankNode;
diff --git a/packages/xforms-engine/src/client/unsupported/RankNode.ts b/packages/xforms-engine/src/client/unsupported/RankNode.ts
deleted file mode 100644
index b64d2f083..000000000
--- a/packages/xforms-engine/src/client/unsupported/RankNode.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { RankControlDefinition } from '../../parse/body/control/RankControlDefinition.ts';
-import type {
- UnsupportedControlDefinition,
- UnsupportedControlNode,
-} from './UnsupportedControlNode.ts';
-
-export interface RankNodeDefinition extends UnsupportedControlDefinition {
- readonly bodyElement: RankControlDefinition;
-}
-
-export interface RankNode extends UnsupportedControlNode {
- readonly nodeType: 'rank';
- readonly definition: RankNodeDefinition;
-}
diff --git a/packages/xforms-engine/src/client/unsupported/UnsupportedControlNode.ts b/packages/xforms-engine/src/client/unsupported/UnsupportedControlNode.ts
index 0c606e4a5..f58584d0b 100644
--- a/packages/xforms-engine/src/client/unsupported/UnsupportedControlNode.ts
+++ b/packages/xforms-engine/src/client/unsupported/UnsupportedControlNode.ts
@@ -1,6 +1,5 @@
import type { UnknownAppearanceDefinition } from '../../parse/body/appearance/unknownAppearanceParser.ts';
import type { RangeControlDefinition } from '../../parse/body/control/RangeControlDefinition.ts';
-import type { RankControlDefinition } from '../../parse/body/control/RankControlDefinition.ts';
import type { UploadControlDefinition } from '../../parse/body/control/UploadControlDefinition.ts';
import type { LeafNodeDefinition } from '../../parse/model/LeafNodeDefinition.ts';
import type { BaseNode, BaseNodeState } from '../BaseNode.ts';
@@ -17,7 +16,6 @@ export interface UnsupportedControlNodeState extends BaseNodeState {
export type UnsupportedControlElementDefinition =
| RangeControlDefinition
- | RankControlDefinition
| UploadControlDefinition;
export interface UnsupportedControlDefinition extends LeafNodeDefinition {
diff --git a/packages/xforms-engine/src/index.ts b/packages/xforms-engine/src/index.ts
index c93f0eb15..f6a5d93bc 100644
--- a/packages/xforms-engine/src/index.ts
+++ b/packages/xforms-engine/src/index.ts
@@ -24,6 +24,7 @@ export type * from './client/InputNode.ts';
export type * from './client/ModelValueNode.ts';
export type * from './client/NoteNode.ts';
export type * from './client/OpaqueReactiveObjectFactory.ts';
+export type * from './client/RankNode.ts';
export type * from './client/repeat/RepeatInstanceNode.ts';
export type * from './client/repeat/RepeatRangeControlledNode.ts';
export type * from './client/repeat/RepeatRangeUncontrolledNode.ts';
@@ -40,7 +41,6 @@ export type * from './client/SubtreeNode.ts';
export type * from './client/TextRange.ts';
export type * from './client/TriggerNode.ts';
export type * from './client/unsupported/RangeNode.ts';
-export type * from './client/unsupported/RankNode.ts';
export type * from './client/unsupported/UploadNode.ts';
export type * from './client/validation.ts';
export type * from './client/ValueType.ts';
diff --git a/packages/xforms-engine/src/instance/RankControl.ts b/packages/xforms-engine/src/instance/RankControl.ts
new file mode 100644
index 000000000..eb62731e7
--- /dev/null
+++ b/packages/xforms-engine/src/instance/RankControl.ts
@@ -0,0 +1,26 @@
+import type { ValueType } from '../client/ValueType.ts';
+import { ValueNode } from './abstract/ValueNode.ts';
+import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
+import type { ValidationContext } from './internal-api/ValidationContext.ts';
+import type {
+ ClientReactiveSubmittableValueNode,
+} from './internal-api/submission/ClientReactiveSubmittableValueNode.ts';
+import type {
+ RankDefinition,
+ RankValues,
+ RankNode,
+} from '../client/RankNode.ts';
+
+export class RankControl
+ extends ValueNode, RankValues, RankValues>
+ implements
+ RankNode,
+ XFormsXPathElement,
+ EvaluationContext,
+ ValidationContext,
+ ClientReactiveSubmittableValueNode
+{
+
+}
+
+export type AnyRankControl = RankControl;
diff --git a/packages/xforms-engine/src/instance/unsupported/RankControl.ts b/packages/xforms-engine/src/instance/unsupported/RankControl.ts
deleted file mode 100644
index 06a483485..000000000
--- a/packages/xforms-engine/src/instance/unsupported/RankControl.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { UnsupportedControl } from '../abstract/UnsupportedControl.ts';
-import type { ValueContext } from '../internal-api/ValueContext.ts';
-
-export class RankControl extends UnsupportedControl<'rank'> implements ValueContext {
- readonly nodeType = 'rank';
-
- // ValueContext
- readonly contextNode = this;
-}