Getting Started

Contribution

A comprehensive guide on contributing to EletroDS, including project structure, development workflow, and best practices.

A comprehensive guide on contributing to EletroDS, including project structure, development workflow, and best practices.

Mercado Eletrônico and EletroDS grow even more with your initiative to contribute . Your contributions, whether through bug reports, pull requests, or feedback, are essential to continuously improve this library.

Before reporting a bug or requesting a feature, make sure that you have read through our documentation and existing issues.

Project Structure

EletroDS is organized as a monorepo using pnpm workspaces and Turborepo for efficient package management. Here's an overview of the key directories and files:

packages/ui/app/index.ts
// Main entry point for @mercadoeletronico/eds-next
// Exports all components, composables, and utilities

export * from "./components";

Package Overview

PackageDescriptionPath
@mercadoeletronico/eds-uiNuxt UI wrapper layerpackages/ui/
@mercadoeletronico/eds-tokensDesign tokens (colors, spacing, etc.)packages/tokens/
@mercadoeletronico/eslint-configShared ESLint configurationpackages/eslint-config/
@mercadoeletronico/ts-configShared TypeScript configurationpackages/ts-config/

Key Directories


icon: i-lucide-package title: packages/core/src/components/ color: primary


All Vue components organized by name. Each component has its own folder with theme configuration.


icon: i-lucide-palette title: packages/tokens/src/ color: secondary


Design tokens including colors, spacing, typography, shadows, and theme definitions.


icon: i-lucide-test-tube title: packages/playwright/tests/ color: success


E2E tests using Playwright for comprehensive component testing.


icon: i-lucide-book-open title: docs/content/ color: info


Documentation written in Markdown with Nuxt Content for interactive examples.

Getting Started

Jira Board

We use Jira to manage our development tasks and track progress. All available tasks can be found on our Jira board.

Taking a Task

Browse the Jira board to find an available task

Look for tasks that are unassigned and match your skills.

Communicate with the EDS team PO before assuming the task

This ensures proper coordination and avoids duplicate work.

Assign the task to yourself

Move the task to "In Development" status.

Add a comment using the validation template

Use the template provided below to document your progress.

Validation Template

When you take a task, add the following template as a comment in the Jira task:

✨ For validation

**Component Developed:** [Component Name]
**Link:** [Link to component documentation or example]
**Description:** [Brief description of what was implemented]

**Screenshots/Video:**
[Attach screenshots or video demonstrating the component - required for visual validation]

**Testing:**

- [ ] Cypress tests written and passing
- [ ] Component tested in different scenarios
- [ ] Cross-browser testing completed (if applicable)

**Documentation:**

- [ ] Documentation created/updated following Documentation Guide
- [ ] Examples provided
- [ ] Props, events, and slots documented
The component link, screenshot/video, and description are required for validation. Make sure to provide clear visual evidence of what was developed.

Local Development

To begin local development, follow these steps:

Clone the repository

Terminal
git clone <repository-url>
cd eds-next

Install dependencies

Terminal
# Using yarn
pnpm i

Start development

To work on the documentation and run the development server for testing components, run:

Terminal
pnpm docs:dev

This command will start both the documentation server and the development environment for testing components.

IDE Setup

We recommend using VSCode alongside the ESLint extension. You can enable auto-fix and formatting when saving your code:

.vscode/settings.json
{
  "editor.codeActionsOnSave": {
    "source.fixAll": false,
    "source.fixAll.eslint": true
  }
}
Since ESLint is already configured to format the code, there's no need for duplicating functionality with Prettier. If you have it installed in your editor, we recommend disabling it to avoid conflicts.

Linting

You can use the lint command to check for linting errors:

Terminal
pnpm lint        # check for linting errors

Testing

Before submitting a MR, ensure that you run the tests:

Terminal
# Run unit tests
pnpm test

# Run test coverage
pnpm coverage

Writing Unit Tests with Vitest

All components should have corresponding unit tests using Vitest + Vue Test Utils. The test files must be colocated alongside the component source, following the naming convention [ComponentName].test.ts.

Location: packages/ui/app/components/commons/

Test Structure

Each test file should follow this structure:

  1. Imports: Import describe, it and expect from vitest, along with mount from @vue/test-utils.
  2. Mock Components: When needed, create mock components to isolate the behavior being tested.
  3. Describe blocks: Group tests logically using nested describe blocks — the first level for the component and the second for specific features.
  4. Assertions: Use Vitest matchers (toBeDefined, toBe, toContain, etc.).
Example: Test File
import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import { MyComponent } from "./MyComponent";

// 1. Create mocks when needed to isolate the test
const MockChild = {
  name: "MockChild",
  props: {
    title: String,
    count: Number,
  },
  template: '<div class="mock-child">{{ title }} - {{ count }}</div>',
};

describe("MyComponent", () => {
  // 2. Test that the component is created correctly
  it("should create the component correctly", () => {
    const wrapper = mount(MyComponent);
    expect(wrapper).toBeDefined();
  });

  // 3. Test rendering with props
  it("should render with props correctly", () => {
    const wrapper = mount(MyComponent, {
      props: {
        title: "Test",
        count: 42,
      },
    });

    expect(wrapper.find(".my-component").text()).toBe("Test - 42");
  });

  // 4. Test that props are passed correctly to internal components
  it("should pass props to internal components", () => {
    const wrapper = mount(MyComponent, {
      props: {
        title: "Test Component",
        count: 100,
      },
    });

    const child = wrapper.findComponent(MockChild);
    expect(child.props("title")).toBe("Test Component");
    expect(child.props("count")).toBe(100);
  });

  // 5. Test slot behavior
  it("should work with slots", () => {
    const wrapper = mount(MyComponent, {
      slots: {
        default: "Slot content",
      },
    });

    expect(wrapper.text()).toContain("Slot content");
  });

  // 6. Test attributes and CSS classes
  it("should apply attributes and CSS classes", () => {
    const wrapper = mount(MyComponent, {
      props: {
        customClass: "test-class",
      },
    });

    expect(wrapper.find(".my-component").classes()).toContain("test-class");
  });
});
Best Practices
  • Colocation: Test files should live alongside the component source (e.g., MyComponent.ts and MyComponent.test.ts in the same directory).
  • Isolation: Use mock components to isolate the behavior being tested, avoiding external dependencies.
  • Coverage: Maintain coverage above 80%. Reports are generated in target/packages/ui/coverage/.
  • Automatic cleanup: The vitest.setup.ts file already runs cleanup() from @testing-library/vue after each test, so manual cleanup is not needed.
  • Environment: Tests run in a jsdom environment, simulating the browser DOM.

Documentation

Documentation Standard

Our component documentation follows the same structure and conventions used by Nuxt UI, providing a consistent and familiar experience for developers. Each component page is a markdown file located in docs/content/2.components/ and uses Nuxt Content with custom components like ::code-preview for interactive examples.

Creating Component Documentation

When creating or updating component documentation:

Create the markdown file

Add your documentation file in docs/content/2.components/ following the naming convention {order}.{component-name}.md (e.g., 2.button.md).

Add the frontmatter

Every component page must start with a YAML frontmatter block:

---
title: ComponentName
description: A brief description of the component and its purpose.
navigation:
  icon: i-lucide-icon-name
---

Follow the required section structure

The documentation must include the sections described below in order.

Documentation Structure

Component documentation must follow this structure, in order:

SectionDescription
IntroductionA brief description of the component right after the frontmatter.
UsageBasic usage with the default slot or main prop. Shows how to get started with the component.
Prop sectionsOne ## Section per major prop (e.g., Color, Variant, Size, Icon, etc.), each with a ::code-preview block showing a live preview and the corresponding code.
APITechnical reference with tables, divided into Props, Slots, and Emits (see API Section Format below).
ExamplesAdvanced or composite usage patterns (e.g., Button Group, Form Submit).

Using ::code-preview

All visual examples must use the ::code-preview component, which renders a live preview alongside the source code. The structure is:

::code-preview

:me-component-name{prop="value" label="Example"}

#code

\```vue
<template>
<MeComponentName prop="value">Example</MeComponentName>
</template>
\```

::

For examples with multiple items, wrap them in a ::div:

::code-preview

::div{class="flex flex-wrap gap-2"}
:me-component-name{variant="solid" label="Solid"}
:me-component-name{variant="outline" label="Outline"}
::

#code

\```vue
<template>

  <div class="flex flex-wrap gap-2">
    <MeComponentName variant="solid">Solid</MeComponentName>
    <MeComponentName variant="outline">Outline</MeComponentName>
  </div>
</template>
\```

::

API Section Format

The API section must contain up to three subsections with tables, following the same column order as Nuxt UI:

Props

PropDefaultType
label-string
Text content for the component.
color'primary''primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'neutral'
Component color.
disabledfalseboolean
Whether the component is disabled.

Slots

SlotType
default{ label: string }
leading{}
trailing{}

Emits

EventType
click[payload: MouseEvent]
update:modelValue[value: string]

Validation Criteria

Before submitting your work for validation, ensure you meet all the following criteria:

Component Development


icon: i-lucide-check-circle title: Fully Functional color: success


Component is fully functional and works as expected.


icon: i-lucide-palette title: Design Guidelines color: info


Component follows the design system guidelines.


icon: i-lucide-smartphone title: Responsive & Accessible color: primary


Component is responsive and accessible to all users.


icon: i-lucide-shield-check title: Edge Cases color: warning


Component handles edge cases and error states properly.

Testing Checklist

  • Cypress tests are written and passing
  • Component is tested in different scenarios
  • Tests cover main functionality and edge cases
  • Cross-browser testing completed (if applicable)

Documentation Checklist

  • Documentation created/updated following the Documentation Guide
  • Examples provided and working
  • Props, events, and slots are fully documented
  • Documentation is clear and easy to understand

Code Quality Checklist

  • Code follows project conventions
  • ESLint passes without errors
  • No console errors or warnings
  • Code is properly commented where necessary

Submitting Changes

Commit Conventions

We use Jira commit format for commit messages. All commits must include the Jira task code and time tracking.

Commit Format:

MW-XXXXX #time Xd - commit message

Where:

  • MW-XXXXX is the Jira task code
  • #time Xd is the time spent (e.g., 2d for 2 days, 4h for 4 hours)
  • commit message is a brief description of the changes

Examples:

MW-67130 #time 2d - add new Button component variant
MW-67131 #time 4h - resolve modal closing issue
MW-67132 #time 1d - update Button component documentation
MW-67133 #time 1h - update dependencies

Branch Naming Conventions

Branches must follow the naming pattern based on the type of change:

Branch TypePatternDescriptionCreate From
Featurefeature/MW-XXXXXNew features or enhancementsdevelop
Fixfix/MW-XXXXXBug fixesdevelop
Hotfixhotfix/MW-XXXXXUrgent production fixesmaster
Hotfeaturehotfeature/MW-XXXXXUrgent feature implementationsmaster

Making a Merge Request

Update Jira Task

Before creating a MR, update the Jira task with the validation template comment.

Create Branch

Create a branch following the naming conventions:

  • For feature and fix branches: create from develop (e.g., feature/MW-67130, fix/MW-67131)
  • For hotfeature and hotfix branches: create from master (e.g., hotfeature/MW-67133, hotfix/MW-67132)

Make Changes

Implement your changes following the guidelines above.

Test

Ensure all tests pass and linting is clean.

Document

Update documentation if needed.

Commit

Use Jira commit format (e.g., MW-67130 #time 2d - commit message).

Push and Create MR

Push your branch and create a Merge Request. Link the MR to the Jira task.

MR Requirements

Multiple commits are fine; no need to rebase or force push. We'll use Squash and Merge when merging.
  • Follow along the instructions provided when creating a MR
  • Ensure your MR's title includes the Jira task code and follows the commit format (e.g., MW-67130 #time 2d - description)
  • Ensure lint and tests work before submitting the MR
  • Avoid making unrelated changes
  • Include screenshots or videos if the changes are visual

We'll review it promptly. If assigned to a maintainer, they'll review it carefully.

Thanks

Thank you so much for your interest in contributing! We are one ME team