45 lines
1.7 KiB
Markdown
45 lines
1.7 KiB
Markdown
# Mock challenge: BaseButton component
|
||
|
||
Build a reusable Vue 3 button component suitable for a design system. Focus on API design, accessibility, and Vue 3 best practices.
|
||
|
||
**Suggested time: 25–35 minutes**
|
||
|
||
---
|
||
|
||
## Core requirements
|
||
|
||
- Accept a `variant` prop: `primary`, `secondary`, `danger` — each should have visually distinct styles
|
||
- Accept a `size` prop: `sm`, `md`, `lg` — affects padding and font size
|
||
- Accept a `disabled` prop — visually and functionally disables the button
|
||
- Accept a `loading` prop — shows a loading indicator and prevents interaction
|
||
- Use a default `slot` for button label content
|
||
- Explicitly declare a `click` emit
|
||
|
||
---
|
||
|
||
## Accessibility requirements
|
||
|
||
- Use a native `<button>` element — not a `<div>`
|
||
- When `loading` is true, set `aria-busy="true"` and `aria-disabled="true"`
|
||
- When `disabled` is true, use the native `disabled` attribute (not just styling)
|
||
- Ensure visible focus styles are not removed — `outline: none` without a replacement is a fail
|
||
|
||
---
|
||
|
||
## Bonus points
|
||
|
||
- Add an optional `icon` slot for a leading icon
|
||
- Type all props with TypeScript
|
||
- Add a `full-width` prop that makes the button `width: 100%`
|
||
- Write at least one Vitest unit test — e.g. that the click event does not fire when disabled
|
||
|
||
---
|
||
|
||
## Things they'll be watching for
|
||
|
||
- Do you use `defineProps` and `defineEmits` correctly with script setup syntax?
|
||
- Do you use a `computed` to derive CSS classes from props, or inline ternaries everywhere?
|
||
- Do you handle the loading state gracefully — preventing double-clicks, communicating state to screen readers?
|
||
- Do you narrate your thinking as you go?
|
||
|
||
> **Tip:** Before writing any code, spend 1–2 minutes talking through your approach out loud. Interviewers value reasoning over speed. |