inline question preview
- The Core Interaction: Expandable Rows
Challenge: You need to track which single question row is expanded for editing and conditionally show the editor form only for that row.
Svelte 5 Solution: This is a classic state management and conditional rendering task, perfectly handled by $state and {#if} blocks.
$statefor Selection: You'll use a$statevariable to hold the ID of the currently expanded question. Clicking a row will update this variable.
<script lang="ts">
let expandedQuestionId = $state<string | null>(null);
</script>
{#if}for Conditional Rendering: Inside your{#each}block that lists the questions, you'll use an{#if}block to check if the current question's ID matches the one in your state variable. The editor component will only be rendered for that specific row.$statefor Selection: You'll use a$statevariable to hold the ID of the currently expanded question. Clicking a row will update this variable.
<script lang="ts">
let expandedQuestionId = $state<string | null>(null);
</script>
- The Editor Experience: Single View with Live Preview
Challenge: The form needs to update a live preview in real-time as the admin types.
Svelte 5 Solution: This is where Svelte's core reactivity shines. You'll use a $state object to hold the data for the question being edited and bind:value to link the form inputs to it.
$statefor Editable Data: The form will edit a temporary copy of the question's data, held in a$stateobject.bind:valuefor Two-Way Binding: Each form field (<input>for the stem, inputs for the choices) will be bound to a property on the temporary state object usingbind:value.- Reactive Preview: The preview area will simply display the text from that same temporary state object. Because both the form and the preview are reading from the same reactive
$state, any change in an input will instantly and automatically update the preview with no extra code required.
<script lang="ts">
let { question } = $props();
// `editable` is a reactive copy of the question data
let editable = $state({ ...question });
</script>
<div class="editor-layout">
<div class="form-side">
<label>Question Stem:</label>
<textarea bind:value={editable.stem}></textarea>
</div>
<div class="preview-side">
<h3>{editable.stem}</h3>
</div>
</div>
- Content Type Constraint: Multiple Choice Questions (MCQ) Only
Challenge: The form needs to manage a dynamic list of answer choices (adding, editing, deleting).
Svelte 5 Solution: You'll leverage the deep reactivity of $state objects with arrays, combined with an {#each} block.
- Deep Reactivity for Choices: The
choicesproperty on youreditablequestion object will be an array. Because it's part of a$stateproxy, methods like.push()or.splice()will automatically trigger UI updates. {#each}for Dynamic Inputs: You will use an{#each}block to loop over theeditable.choicesarray and render an<input>for each one. Buttons to "Add Choice" or "Remove" will simply call array methods oneditable.choices.
{#each editable.choices as choice, i (i)}
<div>
<input type="text" bind:value={editable.choices[i]} />
<button onclick={() => editable.choices.splice(i, 1)}>Remove</button>
</div>
{/each}
<button onclick={() => editable.choices.push('')}>Add Choice</button>
- The "New Question" Flow
Challenge: A "New Question" button needs to add a blank, expanded editor row to the top of the list.
Svelte 5 Solution: This is a simple state manipulation. The button's onclick handler will modify the main array of questions and set the expandedQuestionId state.
- Event Handling: The "New Question" button will have an
onclickhandler. - Array Manipulation: The handler will create a new, blank question object and add it to the beginning of your main
questionsarray. - State Update: The handler will then immediately set
expandedQuestionIdto the ID of the new question, causing its editor to appear.
// In your main Question Library page
function handleNewQuestion() {
const newQuestion = { id: crypto.randomUUID(), stem: '', choices: [''], ... };
// Add the new question to the top of the reactive array
questions = [newQuestion, ...questions];
// Set the state to expand the new question's editor
expandedQuestionId = newQuestion.id;
}