Designing Dynamic Column Components

From Placeholders To Real Columns

In our previous lesson, we built the foundation of our Kanban board with placeholder divs representing columns. Now we'll transform those static placeholders into dynamic, reusable components. Remember how we created three simple divs labeled "To Do," "In Progress," and "Done"? Those served us well for establishing the layout, but now we need proper Column components that can:

  1. Accept dynamic titles through props
  2. Render child content (which will be tasks in our next lesson)
  3. Maintain the responsive behavior we already implemented

The key difference between our old placeholders and the new components will be their flexibility. Instead of hardcoded text, we'll use Svelte's prop system to make the titles dynamic, and we'll implement proper child content rendering with @render.

Building The Column Component

Let's create a new file called Column.svelte in our components directory. Here's the complete implementation we're working toward:

<script>
  let { title, children } = $props();
</script>

<div class="column">
  <h2>{title}</h2>
  <div class="tasks">
    {@render children?.()}
  </div>
</div>

The $props() function is how we declare component properties in Svelte 5. In this case, we're destructuring two props: title for the column header and children for the content that will be passed between the component's tags. The @render directive is Svelte 5's way of rendering child content — the ?.() syntax safely handles cases where no children exist.

For styling, we'll enhance our previous placeholder styles while maintaining the same responsive behavior:

<style>
  .column {
    background: #f4f4f4;
    padding: 1rem;
    width: 300px;
    min-height: 400px;
    border-radius: 8px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
    display: flex;
    flex-direction: column;
  }

  h2 {
    margin-top: 0;
    font-size: 1.2rem;
    border-bottom: 2px solid #ccc;
    padding-bottom: 0.5rem;
  }
  
  .tasks {
    flex-grow: 1;
  }
  
  @media (max-width: 950px) {
    .column {
      width: 100%;
    }
  }
</style>

Notice we've kept the same width, shadows, and media query from our placeholders, but added better internal structure with proper heading semantics and a flexible task area that will grow to fill available space.

Upgrading The Board

Now let's modify our Board.svelte to use our new Column component. Here's the transformation:

Before (using placeholders):

<div class="board">
  <div class="column-placeholder">To Do</div>
  <div class="column-placeholder">In Progress</div>
  <div class="column-placeholder">Done</div>
</div>

After (using proper components):

<script>
  import Column from './Column.svelte';
</script>

<div class="board">
  <Column title="To Do" />
  <Column title="In Progress" />
  <Column title="Done" />
</div>

The visual output will look nearly identical at this stage, but with better semantic structure. On desktop, you'll still see three columns side by side, and on mobile, they'll stack vertically — exactly as our placeholders did, but now with a more maintainable component architecture.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal