Build a traffic light where the lights switch from green to yellow to red after predetermined intervals and loop indefinitely. Each light should be lit for the following durations:
You are free to exercise your creativity to style the appearance of the traffic light.
1<script setup>2import TrafficLight from './TrafficLight.vue';34const config = {5 red: {6 backgroundColor: 'red',7 duration: 4000,8 next: 'green',9 },10 yellow: {11 backgroundColor: 'yellow',12 duration: 500,13 next: 'red',14 },15 green: {16 backgroundColor: 'green',17 duration: 3000,18 next: 'yellow',19 },20};21</script>2223<template>24 <div class="wrapper">25 <TrafficLight :config="config" initialColor="green" layout="vertical" />26 <TrafficLight :config="config" layout="horizontal" initialColor="green" />27 </div>28</template>2930<style>31.wrapper {32 align-items: center;33 display: flex;34 flex-direction: column;35 gap: 16px;36 justify-content: center;37}38</style>
Traffic lights are simple state machines where each color is a state and each state is shown for a fixed duration before moving to the next. We can capture the state information (how long to remain in each color and which color to transition to) using a simple JavaScript object:
const config = {red: {duration: 4000,next: 'green',},yellow: {duration: 500,next: 'red',},green: {duration: 3000,next: 'yellow',},};
The next field makes the component a timed state machine.
Within the TrafficLight component, currentColor is a ref. A watchEffect schedules the next setTimeout by looking up the current entry in config, and the callback advances the state to that entry's next color. onUnmounted clears the pending timer so it cannot update a removed component.
The rendering of this component is straightforward and can be achieved with Flexbox. With Flexbox, it's also easy to change the layout of the lights from a vertical one to a horizontal one just by changing the flex-direction property.
Vue style and class bindings render the current light and layout, while the polite live region and changing aria-label expose the active color to assistive technology.
It's a good practice to make components reusable by allowing customization of:
We also define the color of each light within the config object so that the TrafficLight component is both state and color agnostic. It's even possible to create two-color and four-color traffic lights just by modifying the config object without having to modify the TrafficLight component's implementation.
For a11y reasons, we add an aria-label to the component to indicate the current light and aria-live="polite" to announce the current active light. The contents of the component (the lights) are for visual purposes and aren't important to screen readers; they can be hidden with aria-hidden="true".
console.log() statements will appear here.