# Testing Methodologies Standards for Bulma
This document outlines the testing methodologies to be followed when developing with the Bulma CSS framework. It covers unit, integration, and end-to-end testing strategies, tailored specifically for Bulma. Adhering to these standards ensures maintainability, performance, and reliability of Bulma-based projects.
## 1. General Testing Principles
### 1.1. Test-Driven Development (TDD)
* **Do This:** Ideally, write tests *before* writing the Bulma-related code (CSS, HTML, or JavaScript). This encourages a clear understanding of requirements and a more testable design. Although strictly enforcing TDD for purely styling changes can be overkill, consider it for complex component interactions or customizations.
* **Don't Do This:** Write tests as an afterthought or skip them altogether.
* **Why:** TDD leads to more robust and well-defined code. It also improves the design by forcing consideration of the component's API and behavior upfront.
### 1.2. Testing Pyramid
* **Do This:** Follow the testing pyramid principle: more unit tests, fewer integration tests, and even fewer end-to-end (E2E) tests.
* **Don't Do This:** Rely disproportionately on E2E tests, as they are slow and brittle. Conversely, having no E2E tests at all leads to not testing critical user flows.
* **Why:** This approach ensures comprehensive testing at different levels, optimizing for speed, cost, and coverage.
### 1.3. Comprehensive Testing
* **Do This:** Ensure to test all possible scenarios and edge cases to deliver a fully functional, well-rounded website
* **Don't Do This:** Only test basic implementations of your website.
* **Why:** Thorough testing improves the website's functionality and user experience.
## 2. Unit Testing of Bulma Components
Unit testing involves isolating and testing individual components or functions that use Bulma classes. Since Bulma is primarily a CSS framework, unit testing often involves verifying the *presence* of specific Bulma classes on HTML elements after a particular interaction. For Javascript components working *with* Bulma ensure isolation and use mocking techniques.
### 2.1. Technologies and Libraries
* **Preferred:** Jest with jsdom, Mocha with Chai and jsdom, or similar JavaScript testing frameworks. These frameworks provide assertion libraries and a DOM environment for simulating browser behavior.
* **Alternative:** Consider Cypress Component Testing (see section 4) if you are heavily reliant on testing component interactions inside of the browser.
### 2.2. Standards
* **Do This:** Use descriptive test names that clearly indicate what is being tested.
* **Do This:** Write tests that assert the correct Bulma classes are applied based on component state or user interaction.
* **Do This:** Mock external dependencies (e.g., API calls, other components) to isolate the unit under test.
* **Don't Do This:** Write tests that are too tightly coupled to the implementation details. Focus on the expected behavior and resulting CSS classes.
* **Why:** Clear test names improve readability and maintainability. Testing for specific classes assures correct styling. Mocking isolates units for accurate testing.
### 2.3. Code Examples
#### Example 1: Testing a ModalComponent
"""javascript
// Modal.test.js
import { ModalComponent } from './ModalComponent'; // Assuming this is a React component
import { JSDOM } from 'jsdom';
const dom = new JSDOM('');
global.document = dom.window.document;
global.window = dom.window;
describe('ModalComponent', () => {
let modal;
beforeEach(() => {
// Setup the DOM
const root = document.getElementById('root');
modal = new ModalComponent(root); // Using a hypothetical "render" method.
modal.render();
});
afterEach(() => {
modal.destroy(); // Cleanup after each test.
});
it('should add the "is-active" class to the modal when opened', () => {
modal.open();
const modalElement = document.querySelector('.modal');
expect(modalElement.classList.contains('is-active')).toBe(true);
});
it('should remove the "is-active" class from the modal when closed', () => {
modal.open(); // Open first, then close.
modal.close();
const modalElement = document.querySelector('.modal');
expect(modalElement.classList.contains('is-active')).toBe(false);
});
it('should trigger a callback function when the close button is clicked', () => {
const onCloseMock = jest.fn();
modal.onClose = onCloseMock;// setting the onClose callback function of whatever framework it is.
modal.render();
const closeButton = document.querySelector('.modal-close');
closeButton.click();
expect(onCloseMock).toHaveBeenCalled();
});
});
// ModalComponent.js (Hypothetical example class - adapt to your framework)
export class ModalComponent {
constructor(rootElement) {
this.rootElement = rootElement;
this.isOpen = false;
}
render() {
//Simple example for illustration -- actual render might use react, vue etc
this.modalElement = document.createElement('div');
this.modalElement.classList.add('modal');
this.modalElement.innerHTML = "
This is the modal content
";
this.rootElement.appendChild(this.modalElement);
this.closeButton = this.modalElement.querySelector(".modal-close");
this.closeButton.addEventListener("click", () => {
this.close();
if (this.onClose) {
this.onClose();
}
});
}
open() {
this.modalElement.classList.add('is-active');
this.isOpen = true;
}
close() {
this.modalElement.classList.remove('is-active');
this.isOpen = false;
}
destroy(){
this.rootElement.removeChild(this.modalElement);
}
}
"""
#### Explanation:
* This example uses Jest and jsdom to simulate a browser environment.
* It tests that the "is-active" class is added/removed when the modal is opened/closed, ensuring correct visual state per Bulma.
* It tests that the "onClose" mock function is triggered when the close button is clicked.
* The actual DOM element is manually created an event listeners are being manually registered so that the javascript behaviour and the rendering with Bulma can be tested. Replace with your favourite framework.
### 2.4. Anti-Patterns
* **Testing implementation details:** Avoid testing *how* a class is added, only that it *is* added under the correct conditions. For example don't check what actual html elements you are creating. Only check that after the proper state, Bulma renders the right classes.
* **Over-reliance on snapshots:** While useful, snapshot tests can easily become outdated. Use them sparingly for verifying complex component structures, but prefer more specific assertions.
* **Skipping tests for "simple" components:** Every component, no matter how small, should have unit tests to ensure its basic functionality.
## 3. Integration Testing with Bulma
Integration testing focuses on verifying the interaction between different components or modules that utilize Bulma. This level of testing ensures that Bulma's classes are correctly applied across multiple components and that the overall layout and styling work as expected.
### 3.1. Technologies and Libraries
* **Preferred:** Same as unit testing (Jest, Mocha) but focusing on component interactions instead of individual units. Cypress Component testing (if not used for unit testing) can be useful here.
* **Consider:** Storybook for isolating and visually testing UI components, particularly when integrated with tools like Chromatic for visual regression testing.
### 3.2. Standards
* **Do This:** Test the interaction between components that rely on Bulma's grid system or other layout features.
* **Do This:** Verify that responsiveness is maintained when components are integrated. Test on different screen sizes (using mocking or simulated viewports).
* **Do This:** Include tests for themes/variations based on modifying CSS variables.
* **Don't Do This:** Re-test individual component behavior that is already covered by unit tests. Focus on the *integration* aspect.
* **Why:** Ensures correct layout and styling across multiple components. Validates responsiveness and theming.
### 3.3. Code Examples
#### Example: Testing a Form with Validation
"""javascript
// Form.test.js
import { FormComponent } from './FormComponent'; // A hypothetical form component
import { JSDOM } from 'jsdom';
const dom = new JSDOM('');
global.document = dom.window.document;
global.window = dom.window;
describe('FormComponent', () => {
let form;
beforeEach(() => {
const root = document.getElementById('root');
form = new FormComponent(root);
form.render();
});
afterEach(() => {
form.destroy();
});
it('should display "is-danger" class on input and feedback message when validation fails', () => {
const inputElement = document.querySelector('#email');
const submitButton = document.querySelector('button[type="submit"]');
// Simulate invalid input
inputElement.value = 'invalid-email';
submitButton.click();
expect(inputElement.classList.contains('is-danger')).toBe(true);
const feedbackMessage = document.querySelector('.help.is-danger');
expect(feedbackMessage).toBeTruthy(); // Assert the element is present
});
it('should remove "is-danger" and feedback upon correction', () => {
const inputElement = document.querySelector('#email');
const submitButton = document.querySelector('button[type="submit"]');
// Simulate invalid input FIRST to trigger the error
inputElement.value = 'invalid-email';
submitButton.click();
// Then, correct it
inputElement.value = 'valid@email.com';
submitButton.click();
expect(inputElement.classList.contains('is-danger')).toBe(false);
const feedbackMessage = document.querySelector('.help.is-danger');
expect(feedbackMessage).toBeFalsy(); // Assert the element is NOT present
});
});
// FormComponent.js (A simplified, hypothetical example)
export class FormComponent {
constructor(rootElement) {
this.rootElement = rootElement;
this.isOpen = false;
}
render() {
this.formElement = document.createElement('form');
this.formElement.innerHTML = "
<p></p>
Submit
";
this.formElement.addEventListener('submit', (event) => {
event.preventDefault();
const emailInput = this.formElement.querySelector('#email');
const emailValue = emailInput.value;
const feedbackMessage = this.formElement.querySelector('.help.is-danger');
if (!this.isValidEmail(emailValue)) {
emailInput.classList.add('is-danger');
feedbackMessage.textContent = 'Please enter a valid email address';
feedbackMessage.style.display = "block"; } else {
emailInput.classList.remove('is-danger');
feedbackMessage.textContent = '';
feedbackMessage.style.display = "none";
}
});
this.rootElement.appendChild(this.formElement);
}
isValidEmail(email) {
// Basic email validation regex.
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
destroy(){
this.rootElement.removeChild(this.formElement);
}
}
"""
#### Explanation:
* This example tests the interaction between a form input and validation logic.
* It asserts that the "is-danger" class is added to the input field and an error message is displayed when the email is invalid, and that these indicators are removed when corrected.
* Demonstrates how to test Bulma's form styling in conjunction with custom validation (a common use case).
* **Testing Responsiveness:** Bulma relies on breakpoints to change its appearance. Use testing frameworks like Cypress to test the appearance of bulma at different viewports.
"""javascript
//Testing responsiveness with Cypress.
describe('Column responsiveness', () => {
it('Should render columns stacked on mobile', () => {
cy.viewport('iphone-6')
cy.visit('/index.html')
cy.get('.column').should('have.css', 'width', '100%')
})
it('Should render columns side-by-side on desktop', () => {
cy.viewport('macbook-13')
cy.visit('/index.html')
cy.get('.column').should('not.have.css', 'width', '100%')
})
})
"""
HTML (index.html). Note: this example assumes there are Bulma columns with the class "column".
"""html
First column
Second column
"""
### 3.4. Anti-Patterns
* **Testing individual Bulma components in isolation:** Integration tests must focus on interactions between components.
* **Ignoring responsiveness:** Failure to test on different screen sizes leads to layout issues on various devices.
* **Overlapping unit and integration tests:** The scope of each test type must be clearly defined to avoid redundancy. Unit should isolate. Integration is the behaviour *between* components.
## 4. End-to-End (E2E) Testing with Bulma
End-to-end (E2E) testing simulates real user scenarios to ensure that the entire application, including its Bulma-based styling and layout, functions correctly from start to finish.
### 4.1. Technologies and Libraries
* **Preferred:** Cypress, Playwright. These frameworks provide a complete testing environment that runs in a real browser.
* **Alternative:** Selenium WebDriver (more complex setup, but widely used).
### 4.2. Standards
* **Do This:** Focus on critical user flows, such as submitting a form, navigating between pages, and interacting with key UI elements.
* **Do This:** Verify that styling is consistent across different pages and states. Pay attention to font sizes, colors, spacing, and overall visual appearance of Bulma classes.
* **Do This:** Run E2E tests in a continuous integration (CI) environment to catch regressions early.
* **Don't Do This:** Overly rely on E2E tests for every small change. Reserve them for verifying critical functionalities.
* **Don't Do This:** Use brittle selectors that are prone to breaking when the UI is updated. Instead add testing-specific data attributes.
* **Why:** Assures end-to-end functionality and visual consistency. Facilitates early regression detection.
### 4.3. Code Examples
#### Example: Testing Form Submission
"""javascript
// cypress/e2e/form_submission.cy.js
describe('Form Submission', () => {
it('should successfully submit the form and display a success message', () => {
cy.visit('/contact'); // Assuming there's a contact page with a form
// Using data-cy attributes for robust selectors
cy.get('input[data-cy="name"]').type('John Doe');
cy.get('input[data-cy="email"]').type('john.doe@example.com');
cy.get('textarea[data-cy="message"]').type('This is a test message.');
cy.get('button[data-cy="submit"]').click(); //Bulma buttons
// Assert that a success message is displayed (assuming Bulma's notification)
cy.get('.notification.is-success')
.should('be.visible')
.contains('Thank you for your message!');
});
it('should display an error message if any of the fields are empty', () => {
cy.visit('/contact'); // Assuming there's a contact page with a form
cy.get('button[data-cy="submit"]').click(); //Bulma buttons
cy.get('.notification.is-danger')
.should('be.visible')
.contains('Please fill in all required fields.');
});
it('should maintain Bulma styling throughout the submission process', () => {
cy.visit('/contact');
cy.get('input[data-cy="name"]')
.should('have.class', 'input') // Bulma's input class
.type('John Doe');
cy.get('button[data-cy="submit"]')
.should('have.class', 'button') // Bulma's button class
.and('have.class', 'is-primary'); // Bulma's primary color
// ... more styling assertions for other elements and states ...
});
});
"""
#### Explanation:
* This example uses Cypress to simulate a user submitting a form.
* It asserts that the form is successfully submitted and a success message is displayed.
* It asserts that Bulma's styling (e.g., "input", "button" classes) is maintained throughout the process.
* It uses "data-cy" attributes to create robust selectors that are less likely to break when the UI is updated.
### 4.4. Anti-Patterns
* **Using CSS classes as selectors:** CSS classes are subject to change during styling updates. Use more specific selectors (e.g., "data-cy" attributes).
* **Relying on hardcoded delays:** Instead, wait for elements to be visible or for specific events to occur. This makes tests more reliable and less prone to timing issues.
* **Skipping visual validation:** E2E tests should include visual validation to ensure that Bulma's styling is correctly applied and that the UI looks as expected. Cypress’s screenshot functionality can be used for this purpose.
## 5. Visual Regression Testing
Visual regression testing is a critical part of ensuring the long-term integrity of Bulma-based designs.
### 5.1. Technologies and Libraries
* **Preferred:** Chromatic (Storybook integration), Percy, Applitools. These tools automate the process of capturing and comparing screenshots of UI components.
### 5.2. Standards
* **Do This:** Integrate visual regression testing into your CI/CD pipeline.
* **Do This:** Establish baseline screenshots for each component and page.
* **Do This:** Review and approve visual changes manually. Treat visual regressions the same way as functional bugs.
* **Don't Do This:** Ignore visual regressions. They often indicate underlying styling issues or unintended side effects.
* **Why:** Detects unintended visual changes early and improves the overall visual quality of the application.
### 5.3. Code Examples
#### Example: Chromatic with Storybook
Ensure that you have storybook setup! Chromatic integrates well with storybook.
1. **Install Chromatic:** "npm install -g chromatic"
2. **Initialize Chromatic:** "chromatic init"
3. **Run Chromatic:** "chromatic"
### 5.4. Anti-Patterns
* **Ignoring small visual differences:** Even seemingly minor visual changes can have a significant impact on the user experience.
* **Not establishing baselines:** Without baselines, there's no reference point for comparison.
## 6. Accessibility (A11y) Testing
### 6.1. Technologies and Libraries
* **Preferred:** axe-core, pa11y, Lighthouse.
* **Integration:** Integrate axe-core into your unit and integration tests. Use pa11y or Lighthouse in your E2E tests.
### 6.2. Standards
* **Do This:** Test all components and pages for WCAG compliance.
* **Do This:** Ensure proper semantic HTML is used (e.g., appropriate use of headings, labels, and ARIA attributes).
* **Do This:** Verify that color contrast ratios meet accessibility standards.
* **Don't Do This:** Assume that Bulma automatically makes your site accessible. It provides the tools but requires careful implementation.
* **Why:** Makes your application accessible to users with disabilities.
### 6.3. Code Examples
#### Example: axe-core in Jest
"""javascript
// Button.test.js
import { ButtonComponent } from './ButtonComponent'; // Hypothetical Bulma button
import { JSDOM } from 'jsdom';
const dom = new JSDOM('');
global.document = dom.window.document;
global.window = dom.window;
const { axe, toHaveNoViolations } = require('jest-axe');
expect.extend(toHaveNoViolations);
describe('ButtonComponent Accessibility', () => {
let button;
beforeEach(() => {
const root = document.getElementById('root');
button = new ButtonComponent(root);
button.render();
});
afterEach(() => {
button.destroy();
});
it('should have no accessibility violations', async () => {
const buttonElement = document.querySelector('button');
const results = await axe(buttonElement);
expect(results).toHaveNoViolations();
});
it('should include an accessible name', async () => {
// Testing for role=button is redundant. Bulma just applies a class
const buttonElement = document.querySelector('button');
if (!buttonElement.getAttribute('aria-label')& !buttonElement.textContent){
//This is not a real violation. More of a reminder that the code needs to have either an Aria-label or a testContent
//Accessibility best practices dictate that a button should have a descriptive name, either via text content or the aria-label attribute
console.warn("REMINDER: Accessible name not found", buttonElement)
}
expect(buttonElement).toBeDefined();
});
});
// ButtonComponent.js
export class ButtonComponent {
constructor(rootElement) {
this.rootElement = rootElement;
this.isOpen = false;
}
render() {
this.buttonElement = document.createElement('button');
this.buttonElement.classList.add('button', 'is-primary');
this.buttonElement.textContent = 'Click me';
this.rootElement.appendChild(this.buttonElement);
}
destroy(){
this.rootElement.removeChild(this.buttonElement);
}
}
"""
### 6.4. Anti-Patterns
* **Ignoring accessibility issues:** Accessibility should be a core consideration, not an afterthought.
* **Assuming color contrast is sufficient:** Use a color contrast checker to verify compliance.
By adhering to these testing methodologies, development teams can ensure the quality, reliability, and accessibility of Bulma-based projects. This document serves as a guide for developers and can be integrated into AI coding assistants to promote best practices.
danielsogl
Created Mar 6, 2025
This guide explains how to effectively use .clinerules
with Cline, the AI-powered coding assistant.
The .clinerules
file is a powerful configuration file that helps Cline understand your project's requirements, coding standards, and constraints. When placed in your project's root directory, it automatically guides Cline's behavior and ensures consistency across your codebase.
Place the .clinerules
file in your project's root directory. Cline automatically detects and follows these rules for all files within the project.
# Project Overview project: name: 'Your Project Name' description: 'Brief project description' stack: - technology: 'Framework/Language' version: 'X.Y.Z' - technology: 'Database' version: 'X.Y.Z'
# Code Standards standards: style: - 'Use consistent indentation (2 spaces)' - 'Follow language-specific naming conventions' documentation: - 'Include JSDoc comments for all functions' - 'Maintain up-to-date README files' testing: - 'Write unit tests for all new features' - 'Maintain minimum 80% code coverage'
# Security Guidelines security: authentication: - 'Implement proper token validation' - 'Use environment variables for secrets' dataProtection: - 'Sanitize all user inputs' - 'Implement proper error handling'
Be Specific
Maintain Organization
Regular Updates
# Common Patterns Example patterns: components: - pattern: 'Use functional components by default' - pattern: 'Implement error boundaries for component trees' stateManagement: - pattern: 'Use React Query for server state' - pattern: 'Implement proper loading states'
Commit the Rules
.clinerules
in version controlTeam Collaboration
Rules Not Being Applied
Conflicting Rules
Performance Considerations
# Basic .clinerules Example project: name: 'Web Application' type: 'Next.js Frontend' standards: - 'Use TypeScript for all new code' - 'Follow React best practices' - 'Implement proper error handling' testing: unit: - 'Jest for unit tests' - 'React Testing Library for components' e2e: - 'Cypress for end-to-end testing' documentation: required: - 'README.md in each major directory' - 'JSDoc comments for public APIs' - 'Changelog updates for all changes'
# Advanced .clinerules Example project: name: 'Enterprise Application' compliance: - 'GDPR requirements' - 'WCAG 2.1 AA accessibility' architecture: patterns: - 'Clean Architecture principles' - 'Domain-Driven Design concepts' security: requirements: - 'OAuth 2.0 authentication' - 'Rate limiting on all APIs' - 'Input validation with Zod'
# State Management Standards for Bulma This document outlines best practices for managing application state within a Bulma-based project. Bulma, being a CSS framework, doesn't inherently handle state management. Therefore, we must rely on external JavaScript libraries and patterns to create dynamic and interactive user interfaces. The goal is to build maintainable, scalable, and performant applications. These standards apply specifically to how state management interacts with and enhances Bulma's styling and components. ## 1. Guiding Principles * **Unidirectional Data Flow:** Data flows in a single direction, making debugging and understanding data changes simpler. This is generally achieved with a component tree where data updates are passed down and events are notified up. * **Separation of Concerns:** Separate the presentation layer (Bulma's CSS & HTML structure) from the application logic and state management. This makes the application more modular and testable. * **Predictable State:** State changes should be predictable, using clearly defined actions. * **Immutability:** Favor immutability when managing state to prevent unexpected side effects and facilitate easier debugging. Immutable data structures ensure that once created, they cannot be changed. This is a core tenet of robust state management. * **Performance:** Avoid unnecessary re-renders by strategically managing state updates and leveraging component memoization techniques. Optimize data structures for efficient lookups and updates. How this impacts Bulma styling should be considered (e.g., avoid frequent class name changes that trigger style recalculations). ## 2. State Management Approaches Several state management libraries integrate well with Bulma. The choice depends on project complexity and team familiarity. ### 2.1. Component-Local State (React useState, Vue Ref, etc.) * **Description:** Each component manages its own state. Suitable for small, self-contained components with limited interactivity. * **Do This:** Use component-local state for simple interactions, such as toggling a Bulma modal's visibility or managing form input values directly within the component displaying the input. * **Don't Do This:** Overuse component-local state for data shared across multiple, unrelated components. This leads to prop drilling and difficult-to-manage state. **Example (React):** """jsx import React, { useState } from 'react'; function BulmaModal() { const [isActive, setIsActive] = useState(false); const toggleModal = () => { setIsActive(!isActive); }; return ( <div> <button className="button" onClick={toggleModal}> Toggle Modal </button> <div className={"modal ${isActive ? 'is-active' : ''}"}> <div className="modal-background"></div> <div className="modal-content"> <p>Modal content goes here.</p> </div> <button className="modal-close is-large" aria-label="close" onClick={toggleModal}></button> </div> </div> ); } export default BulmaModal; """ **Why:** Simplifies component logic for isolated UI elements. The CSS class updates in conjunction with user clicks is well handled in one component. ### 2.2. Context API (React) / Provide/Inject (Vue) * **Description:** Provides a way to pass data through the component tree without having to pass props down manually at every level. * **Do This:** Use for application-wide state that many components need access to, such as user authentication status, theme preferences, or language settings. For example, storing a "theme" object and updating Bulma class names based on the "theme" variables. * **Don't Do This:** Using context to store data that changes frequently, especially if components that consume the context are deeply nested. This can cause unnecessary re-renders. * **Performance Note:** Be mindful of the consumer components. When the context value changes, all components consuming the context will re-render. **Example (React):** """jsx import React, { createContext, useContext, useState } from 'react'; const ThemeContext = createContext(); function ThemeProvider({ children }) { const [theme, setTheme] = useState({ primaryColor: 'is-primary', textColor: 'has-text-dark', }); const toggleTheme = () => { setTheme((prevTheme) => ({ primaryColor: prevTheme.primaryColor === 'is-primary' ? 'is-info' : 'is-primary', textColor: prevTheme.textColor === 'has-text-dark' ? 'has-text-light' : 'has-text-dark', })); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); } function ThemedButton() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <button className={"button ${theme.primaryColor}"} onClick={toggleTheme}> Toggle Theme </button> ); } function ThemedText({ children }) { const { theme } = useContext(ThemeContext); return <p className={theme.textColor}>{children}</p>; } function App() { return ( <ThemeProvider> <div className="container"> <ThemedButton /> <ThemedText>This is some themed text.</ThemedText> </div> </ThemeProvider> ); } export default App; """ **Why:** Context API simplifies accessing shared state values across multiple components without prop drilling, leading to organized theming and styling. "ThemedButton" uses the "primaryColor" variable to update a Bulma button. "ThemedText" applies a text color. When the "ThemeContext" is updated via "toggleTheme" all consuming components (in this case "ThemedButton" and "ThemedText") will rerender. ### 2.3. Redux * **Description:** A predictable state container for JavaScript apps. Centralizes the application state in a single store, making it easier to manage and debug. * **Do This:** Use for complex applications with substantial state and data interactions across many views. Good for managing global application data (e.g., user profiles, shopping cart contents, complex filter states). * **Don't Do This:** Overuse Redux for small single-page applications where component-local state or Context API would suffice. Introduces boilerplate and complexity. **Example (React with Redux):** """jsx // actions.js export const SET_MODAL_ACTIVE = 'SET_MODAL_ACTIVE'; export const setModalActive = (isActive) => ({ type: SET_MODAL_ACTIVE, payload: isActive, }); // reducer.js const initialState = { isModalActive: false, }; function modalReducer(state = initialState, action) { switch (action.type) { case SET_MODAL_ACTIVE: return { ...state, isModalActive: action.payload, }; default: return state; } } export default modalReducer; // store.js import { configureStore } from '@reduxjs/toolkit'; import modalReducer from './reducer'; const store = configureStore({ reducer: { modal: modalReducer, }, }); export default store; // BulmaModal.jsx import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { setModalActive } from './actions'; function BulmaModal() { const dispatch = useDispatch(); const isModalActive = useSelector((state) => state.modal.isModalActive); const toggleModal = () => { dispatch(setModalActive(!isModalActive)); }; return ( <div> <button className="button" onClick={toggleModal}> Toggle Modal </button> <div className={"modal ${isModalActive ? 'is-active' : ''}"}> <div className="modal-background"></div> <div className="modal-content"> <p>Modal content goes here.</p> </div> <button className="modal-close is-large" aria-label="close" onClick={toggleModal}></button> </div> </div> ); } export default BulmaModal; // App.jsx import React from 'react'; import { Provider } from 'react-redux'; import store from './store'; import BulmaModal from './BulmaModal'; function App() { return ( <Provider store={store}> <BulmaModal /> </Provider> ); } export default App; """ **Why:** Redux centralizes state management allowing components across the application to access and modify the state in a predictable way. In this case, a centrally controlled "isModalActive" dictates the Bulma modal's open/close state. ### 2.4. Zustand * **Description:** A small, fast, and scalable bearbones state-management solution using simplified flux principles. Less boilerplate than Redux. * **Benefits:** Lightweight and easy to learn. Can integrate well with React and other frameworks. Improves productivity. **Example:** """jsx import React from 'react'; import { create } from 'zustand' const useStore = create((set) => ({ isModalActive: false, toggleModal: () => set((state) => ({ isModalActive: !state.isModalActive })), })) function BulmaModal() { const { isModalActive, toggleModal } = useStore() return ( <div> <button className="button" onClick={toggleModal}> Toggle Modal </button> <div className={"modal ${isModalActive ? 'is-active' : ''}"}> <div className="modal-background"></div> <div className="modal-content"> <p>Modal content goes here.</p> </div> <button className="modal-close is-large" aria-label="close" onClick={toggleModal}></button> </div> </div> ); } export default BulmaModal; """ **Why:** Zustand offers a simpler approach than Redux, reducing boilerplate and enabling easier state updates for Bulma components. The state definition and modifiers are colocated with the component, making the code more maintainable in certain cases. ### 2.5. MobX * **Description:** Uses reactive functions to automatically update relevant components when state changes. * **Do This:** Consider for applications requiring fine-grained reactivity and automatic dependency tracking. * **Don't Do This:** Avoid if you prefer more explicit control over state updates and data flow. Can be harder to debug initially due to its "magic". **Example (React with MobX):** """jsx import React from 'react'; import { makeObservable, observable, action } from 'mobx'; import { observer } from 'mobx-react-lite'; class ModalState { isModalActive = false; constructor() { makeObservable(this, { isModalActive: observable, toggleModal: action }); } toggleModal = () => { this.isModalActive = !this.isModalActive; } } const modalState = new ModalState(); const BulmaModal = observer(() => { return ( <div> <button className="button" onClick={modalState.toggleModal}> Toggle Modal </button> <div className={"modal ${modalState.isModalActive ? 'is-active' : ''}"}> <div className="modal-background"></div> <div className="modal-content"> <p>Modal content goes here.</p> </div> <button className="modal-close is-large" aria-label="close" onClick={modalState.toggleModal}></button> </div> </div> ); }); export default BulmaModal; """ **Why:** MobX enables reactive updates to Bulma style classes. Changes to "modalState.isModalActive" automatically trigger a re-render for the modal. ### 2.6. Vuex * **Description:** Vue’s official state management library. Follows the Flux pattern with a central store, mutations, actions, and getters. * **Do This:** Use for medium to large Vue applications that need a centralized and predictable state management solution especially useful in areas where Bulma components are being dynamically composed and styled. * **Don't Do This:** For small projects, the overhead of setting up Vuex might outweigh its benefits. **Example (Vue with Vuex):** """vue // store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { isModalActive: false }, mutations: { setModalActive (state, payload) { state.isModalActive = payload } }, actions: { toggleModal ({ commit, state }) { commit('setModalActive', !state.isModalActive) } }, getters: { isModalActive: state => state.isModalActive } }) // BulmaModal.vue <template> <div> <button class="button" @click="toggleModal"> Toggle Modal </button> <div class="modal" :class="{'is-active': isModalActive}"> <div class="modal-background"></div> <div class="modal-content"> <p>Modal content goes here.</p> </div> <button class="modal-close is-large" aria-label="close" @click="toggleModal"></button> </div> </div> </template> <script> import { mapGetters, mapActions } from 'vuex' export default { computed: { ...mapGetters(['isModalActive']) }, methods: { ...mapActions(['toggleModal']) } } </script> // App.vue <template> <div id="app"> <BulmaModal /> </div> </template> <script> import BulmaModal from './components/BulmaModal.vue' export default { components: { BulmaModal } } </script> """ **Why:** Vuex provides structured state management in Vue apps, allowing centralized control over "isModalActive", impacting Bulma's "is-active" class. ## 3. Data Fetching and Caching * **Description:** How your application retrieves and stores data from external sources (e.g., APIs). * **Do This:** * Use libraries like "axios", "fetch", or "swr" (for React) for network requests. * Implement caching strategies to reduce API calls. * Handle loading and error states gracefully using Bulma's progress bars, loading spinners, or notification components. * **Don't Do This:** Make direct API calls inside components without managing loading states, or error handling. Don't store sensitive data (e.g., API keys) directly in the client-side code. **Example (React with "swr" and Bulma loading state):** """jsx import React from 'react'; import useSWR from 'swr'; const fetcher = (...args) => fetch(...args).then((res) => res.json()); function UserProfile() { const { data, error } = useSWR('/api/user', fetcher); if (error) return <div>Failed to load</div>; if (!data) return <progress className="progress is-small is-primary" max="100">15%</progress>; // Bulma loading indicator return ( <div> <h1>{data.name}</h1> <p>{data.email}</p> </div> ); } export default UserProfile; """ **Why:** "swr" handles caching and revalidation, improving performance. Bulma's "progress" component provides visual feedback during data loading. Improves the UX. ## 4. Immutability * **Description:** Treating data as immutable ensures that it cannot be modified after creation. Instead, new copies are created with the required changes. * **Do This:** * Use immutable data structures from libraries like "Immutable.js". * When updating arrays or objects, make use of spread syntax ("...") or "Array.map()", "Array.filter()", "Object.assign()". * **Don't Do This:** Directly modifying existing objects or arrays. This leads to unpredictable behavior and difficulties in debugging. **Example (Array update using spread syntax):** """javascript const originalArray = [1, 2, 3]; const newArray = [...originalArray, 4]; // Creates a new array [1, 2, 3, 4] """ **Example (Object update using spread syntax):** """javascript const originalObject = { name: 'John', age: 30 }; const newObject = { ...originalObject, age: 31 }; // Creates a new object { name: 'John', age: 31 } """ **Why:** Improves predictability by clearly defining the impact of changes, especially when working with complex Bulma-styled components. Makes debugging easier as you can easily track where state changes occur. Enables easier state reconciliation in complex applications. ## 5. Integrating with Bulma * **Bulma's Responsiveness:** When managing state, consider Bulma's responsive design principles. Update state based on screen size or device orientation to adapt the layout dynamically. For example, managing visibility of elements for mobile vs. desktop. * **Bulma Components State:** Use state to control the "is-active", "is-loading", "is-disabled", and other modifiers that control Bulma component appearance and behavior. * **Custom Theming:** Manage theme variables in your state and dynamically apply the appropriate Bulma classes based on these variables. **Example (Managing visibility based on screen size):** """jsx import React, { useState, useEffect } from 'react'; function ResponsiveComponent() { const [isMobile, setIsMobile] = useState(window.innerWidth < 768); // Bulma's breakpoint below tablet useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth < 768); }; window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); }; }, []); return ( <div className={" ${isMobile ? 'is-hidden-desktop' : 'is-hidden-mobile'}"}> {isMobile ? 'This is visible on mobile' : 'This is visible on desktop'} </div> ); } export default ResponsiveComponent; """ **Why:** Provides responsive design adhering to the principles of mobile first, making the site usable at different screen sizes. The "is-hidden-desktop" and "is-hidden-mobile" are Bulma utility classes. ## 6. Testing * **Unit Tests:** Test individual components and state management logic (reducers, actions, etc.) in isolation. * **Integration Tests:** Test how components interact with each other and the state management system. * **End-to-End Tests:** Test the entire application flow from the user's perspective. **Example (Simple Unit Test - React with Jest):** """javascript // BulmaModal.test.js import React from 'react'; import { render, fireEvent } from '@testing-library/react'; import BulmaModal from './BulmaModal'; import { Provider } from 'react-redux'; import store from './store'; test('Toggles modal visibility on button click', () => { const { getByText, queryByRole } = render( <Provider store={store}> <BulmaModal /> </Provider> ); const button = getByText('Toggle Modal'); fireEvent.click(button); const modal = queryByRole('dialog'); //Assuming the modal has role="dialog" expect(modal).toBeInTheDocument(); fireEvent.click(button); expect(queryByRole('dialog')).not.toBeInTheDocument(); }); """ **Why:** Solid tests ensure the state management is behaving as expected; especially critical for toggling the state which affect Bulma CSS classes applied. ## 7. Performance Optimization * **Memoization:** Use "React.memo" to prevent unnecessary re-renders of Bulma components. * **Virtualization:** For large lists, use virtualization libraries like "react-window" to render only the visible items. * **Debouncing/Throttling:** Limit the frequency of state updates triggered by user input. * **Selective Updates:** Update only the specific parts of the state that need to be changed. Avoid unnecessary updates to application-wide context. **Example (Memoization with React.memo):** """jsx import React from 'react'; const BulmaButton = React.memo(function BulmaButton({ onClick, children }) { console.log('BulmaButton rendered'); // Check when it re-renders return ( <button className="button is-primary" onClick={onClick}> {children} </button> ); }); export default BulmaButton; """ **Why:** "React.memo" prevents re-renders if the Bulma button's props haven't changed, improving performance, especially useful when styled with many Bulma elements. Be careful to test performance optimizations and ensure they are providing the gains expected. ## 8. Security Considerations * **Never Store Sensitive Data in State:** Avoid storing passwords, API keys, or other sensitive information directly in the client-side state. * **Sanitize User Input:** When using user input to update Bulma components (e.g., dynamically adding classes), sanitize the input to prevent cross-site scripting (XSS) vulnerabilities. Use established sanitation libraries to properly sanitize data as it enters your application. * **Rate Limiting:** Implement rate limiting for API requests to prevent abuse. * **Authentication and Authorization:** Ensure proper authentication and authorization mechanisms are in place to protect sensitive data. **Example (Sanitizing user input before adding classes):** """javascript import DOMPurify from 'dompurify'; function sanitizeClass(className) { return DOMPurify.sanitize(className, {ALLOWED_TAGS: [], ALLOWED_ATTR: []}); } //Example usage const userInput = "<img src='x' onerror='alert(\"XSS\")' /> malicious-class"; const sanitizedInput = sanitizeClass(userInput); console.log(sanitizedInput); // malicious-class //When adding it to element const element = document.getElementById('myElement'); element.classList.add(sanitizedInput); """ **Why:** Prevents attackers from injecting malicious code that could compromise the application or user data. Preventing execution of JavaScript in class names is critical. By adhering to these guidelines, you can effectively manage application state in your Bulma projects, resulting in more maintainable, scalable, performant, and secure applications. Remember to choose the right state management solution based on the complexity of your project and team expertise. Also keep up-to-date on the latest Bulma versions.
# Component Design Standards for Bulma This document outlines the coding standards for designing components using Bulma, focusing on reusability, maintainability, and performance. Adhering to these standards will ensure consistency and quality across your projects. ## 1. Component Structure and Organization ### 1.1 Modularization **Do This:** * Break down complex UI into smaller, self-contained components. Each component should have a specific purpose ("Single Responsibility Principle"). * Use a consistent directory structure for organizing components. A common pattern is: """ components/ ├── MyComponent/ # Directory for each component │ ├── MyComponent.vue # Main component file (if using Vue.js) │ ├── MyComponent.js # Component logic (if not using a framework) │ ├── MyComponent.scss # Component-specific styles │ └── MyComponent.stories.js # Storybook stories for the component └── AnotherComponent/ ├── AnotherComponent.vue ├── AnotherComponent.js └── AnotherComponent.scss """ **Don't Do This:** * Create monolithic components that handle multiple unrelated functionalities. * Mix component-specific styles directly into global stylesheets. * Lack of a clear folder structure, making it difficult to locate and manage components. **Why:** Modular components are easier to understand, test, and reuse. Consistent structure improves maintainability and collaboration. **Example (Vue.js):** """vue <!-- components/Button/Button.vue --> <template> <button class="button" :class="typeClass" :disabled="disabled" @click="$emit('click')" > {{ label }} </button> </template> <script> export default { name: 'Button', props: { label: { type: String, required: true }, type: { type: String, default: 'primary', validator: (value) => ['primary', 'secondary', 'info', 'success', 'warning', 'danger'].includes(value) }, disabled: { type: Boolean, default: false } }, computed: { typeClass() { return "is-${this.type}"; } } }; </script> <style lang="scss" scoped> /* components/Button/Button.scss */ .button { &.is-primary { @extend .is-primary; // ... other style overrides if needed. Leverage Bulma's variables if desired. } &.is-secondary { @extend .is-info; // Example usage. Different Bulma Color } // Additional specific styling rules for the component } </style> """ ### 1.2 Using Bulma's CSS Classes **Do This:** * Leverage Bulma's built-in classes for common UI elements and layouts. This allows you to take advantage of the grid system, modifiers, and helpers that Bulma provides. * Customize Bulma's variables through a separate "_variables.scss" file to maintain a consistent branding across the application without modifying the Bulma core files. * Use Bulma's modifier classes (e.g., "is-primary", "is-success", "is-small") for consistent styling and theming. * Utilize Bulma's helper classes (e.g., "is-hidden", "is-pulled-left", "has-text-centered") for utility styling. **Don't Do This:** * Overly rely on custom CSS or JavaScript when Bulma provides built-in solutions. * Modify Bulma's core CSS files directly. * Ignore Bulma's semantic class names and create custom names that duplicate Bulma's functionality. **Why:** Using Bulma effectively reduces development time, ensures visual consistency, and simplifies maintenance by relying on a well-documented and established CSS framework. **Example:** """html <button class="button is-primary is-medium"> Click me </button> <div class="columns"> <div class="column is-half"> Column 1 </div> <div class="column is-half"> Column 2 </div> </div> """ **Example of using Bulma Variables (create a "_variables.scss" file and import before Bulma):** """scss // _variables.scss $primary: #ff385f; // Custom primary color, Airbnb style $family-sans-serif: "Nunito", sans-serif; // Import Bulma @import "~bulma/bulma"; """ ### 1.3 Component Communication **Do This:** * Use props to pass data from parent to child components. * Use events to communicate from child to parent components. * For complex state management, consider using a state management library like Vuex or Redux (especially within JS frameworks) **Don't Do This:** * Directly modify props within child components. * Rely on global variables or event buses for inter-component communication where props/events would suffice **Why:** Explicit data flow through props and events ensures predictable behavior and makes it easier to reason about the component's state and interactions. Centralized state management improves organization and simplifies debugging in larger applications. **Example (Vue.js):** """ vue <!-- ParentComponent.vue --> <template> <div> <ChildComponent :message="parentMessage" @customEvent="handleEvent" /> <p>Received event data: {{ receivedData }}</p> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { parentMessage: 'Hello from parent!', receivedData: '' }; }, methods: { handleEvent(data) { this.receivedData = data; } } }; </script> <!-- ChildComponent.vue --> <template> <button class="button is-primary" @click="emitEvent"> Click to emit event </button> </template> <script> export default { props: { message: { type: String, required: true } }, methods: { emitEvent() { this.$emit('customEvent', 'Data from child'); } } }; </script> """ ## 2. Styling and Theming ### 2.1 Bulma's Sass Structure **Do This:** * Take advantage of Bulma's Sass structure. Import the "bulma/bulma.sass" file into your project's main Sass file. * Override Bulma's variables before importing "bulma/bulma.sass" to customize its appearance without modifying the core files. * Use Sass mixins for sharing styling rules across components. * Organize your Sass files into logical sections (variables, mixins, base styles, components). **Don't Do This:** * Modify Bulma's core Sass files directly. This makes upgrading Bulma more difficult. * Overuse "!important" declarations. Use specificity or Sass variable overrides instead. * Write overly complex or deeply nested Sass rules that can negatively impact performance. **Why:** Bulma's Sass structure allows for easy customization and extension while maintaining a clear separation of concerns. Variables and mixins promote code reuse and consistency. **Example (Directory Structure):** """ assets/ ├── sass/ # Main Sass directory │ ├── main.scss # Main Sass file │ ├── _variables.scss # Customized Bulma variables │ ├── _mixins.scss # Custom Sass mixins │ ├── components/ # Component-specific styles │ │ └── _button.scss │ └── base/ # Base styles (e.g., typography, resets) │ └── _typography.scss """ **Example ("main.scss"):** """scss // main.scss @import "./_variables.scss"; // Override Bulma's variables @import "~bulma/bulma"; // Import Bulma // Optionally import your own styles *after* Bulma @import "./_mixins.scss"; @import "./base/_typography.scss"; @import "./components/_button.scss"; """ ### 2.2 Custom Styles and Overrides **Do This:** * Limit custom styles to component-specific styling and high-level theme customizations. Leverage Bulma's core classes as much as possible. * Use clear and descriptive class names for custom styles. Follow a consistent naming convention (BEM is a popular choice). * Ensure that custom styles are responsive and work well across different screen sizes. Use Bulma's responsive modifiers or implement your own media queries. **Don't Do This:** * Create highly specific CSS rules that are difficult to override or maintain. * Use inline styles unless absolutely necessary. * Neglect testing custom styles on different devices and browsers. **Why:** Limiting custom styles ensures that your application remains consistent with Bulma's design principles. Well-organized and responsive styles improve the user experience across all devices. **Example (BEM-style Custom Styling):** """scss /* components/Button/Button.scss */ .button { &.is-primary { @extend .is-primary; // Extend standard Bulma button first // Override further, being specific background-color: $primary; // Custom primary from _variables.scss border-color: darken($primary, 10%); &:hover { background-color: darken($primary, 5%); } } &--large { // BEM modifier block font-size: 1.25rem; padding: 0.75rem 1.5rem; } } """ ### 2.3 Theming **Do This:** * Use Bulma's Sass variables to define your application's theme (colors, fonts, spacing). * Create multiple theme files (e.g., "_theme-light.scss", "_theme-dark.scss") and switch between them using CSS classes or JavaScript. * Utilize CSS custom properties (variables) to store theme values and dynamically update them. **Don't Do This:** * Hardcode theme values directly in CSS rules. * Neglect accessibility considerations when designing your theme (e.g., sufficient contrast ratios). **Why:** Theming allows you to easily switch between different visual appearances and cater to user preferences. CSS custom properties enable dynamic theming without requiring a full page reload. **Example (Dark Theme):** """scss /* _theme-dark.scss */ $background: #222; $text: #fff; $primary: #1e88e5; body { background-color: $background; color: $text; } .button.is-primary { background-color: $primary; } """ ## 3. Component Composition and Patterns ### 3.1 Higher-Order Components (HOCs) or Render Props **Do This (When Using Frameworks):** * Employ Higher-Order Components (HOCs) or render props to share common functionality (e.g., authentication, data fetching) across multiple components where applicable. * Keep HOCs small and focused on a single responsibility. When using vue, functional components are also relevant. **Don't Do This:** * Overuse HOCs or render props, leading to deeply nested component structures. * Create HOCs that tightly couple components to specific implementation details. **Why:** HOCs and render props promote code reuse and separation of concerns. They allow you to inject functionality into components without modifying their core logic. **Example (React):** """jsx // withAuthentication.jsx (HOC) import React from 'react'; const withAuthentication = (WrappedComponent) => { return class extends React.Component { constructor(props) { super(props); this.state = { isAuthenticated: localStorage.getItem('token') !== null }; } render() { if (this.state.isAuthenticated) { return <WrappedComponent {...this.props} />; } else { return <div>Please log in to view this content.</div>; } } }; }; export default withAuthentication; // MyComponent.jsx import React from 'react'; import withAuthentication from './withAuthentication'; const MyComponent = (props) => { return <div>This component requires authentication.</div>; }; export default withAuthentication(MyComponent); """ ### 3.2 Compound Components **Do This (Where Frameworks allow):** * Use compound components to create more complex UI patterns with implicit state sharing. * Clearly document the interaction between the parent and child components. **Don't Do This:** * Make the relationship between compound components too implicit or confusing. * Overuse compound components when simpler composition techniques would suffice. **Why:** Compound components simplify complex UI patterns by encapsulating related components and their interactions. **Example (React):** """jsx // Tabs.jsx import React, { createContext, useState, useContext } from 'react'; const TabsContext = createContext(); const Tabs = ({ children, defaultIndex = 0 }) => { const [selectedIndex, setSelectedIndex] = useState(defaultIndex); return ( <TabsContext.Provider value={{ selectedIndex, setSelectedIndex }}> <div className="tabs"> <ul>{children}</ul> </div> </TabsContext.Provider> ); }; const Tab = ({ children, index }) => { const { selectedIndex, setSelectedIndex } = useContext(TabsContext); const isActive = selectedIndex === index; return ( <li className={isActive ? 'is-active' : ''}> <a onClick={() => setSelectedIndex(index)}>{children}</a> </li> ); }; export { Tabs, Tab }; // Usage <Tabs> <Tab index={0}>Tab 1</Tab> <Tab index={1}>Tab 2</Tab> </Tabs> """ ### 3.3 Mixins (for styling) **Do This:** * Create Sass mixins for common styling patterns or Bulma overrides. * Use descriptive names for your mixins. * Pass parameters to your mixins to make them flexible and reusable. **Don't Do This:** * Create overly complex mixins that are difficult to understand or maintain. * Duplicate code when a mixin could be used instead. **Why:** Sass mixins promote code reuse, reduce redundancy, and improve maintainability. **Example:** """scss // _mixins.scss @mixin box-shadow($shadow...) { box-shadow: $shadow; // Vendor prefixes if needed -webkit-box-shadow: $shadow; } .my-element { @include box-shadow(0 2px 4px rgba(0, 0, 0, 0.1)); } """ ## 4. Accessibility ### 4.1 Semantic HTML **Do This:** * Use semantic HTML elements (e.g., "<nav>", "<article>", "<aside>") to provide structure and meaning to your content. * Use proper heading levels (<h1> to <h6>) to create a logical document outline. * Use "<button>" elements for interactive elements that trigger actions, and "<a>" elements for navigation links. **Don't Do This:** * Use "<div>" or "<span>" elements for everything, without considering their semantic meaning. * Use heading levels purely for styling purposes. * Use "<a>" elements as buttons unless they navigate to a new page or section. **Why:** Semantic HTML improves accessibility for users with disabilities and helps search engines understand the content of your page. **Example:** """html <nav class="navbar" role="navigation" aria-label="main navigation"> <!-- Navbar content --> </nav> <article> <h1>Article Title</h1> <p>Article content...</p> </article> """ ### 4.2 ARIA Attributes **Do This:** * Use ARIA attributes to provide additional information about interactive elements and their state. * Use "aria-label" to provide a text alternative for elements that don't have visible text. * Use "aria-hidden="true"" to hide decorative elements from screen readers. * Test your components with screen readers (e.g., VoiceOver, NVDA) to ensure they are accessible. **Don't Do This:** * Overuse ARIA attributes or use them incorrectly. * Rely solely on ARIA attributes without providing semantic HTML. * Forget to update ARIA attributes when the state of an element changes dynamically. **Why:** ARIA attributes enhance accessibility for users with disabilities by providing assistive technologies with information about the role, state, and properties of UI elements. **Example:** """html <button class="button is-primary" aria-label="Close"> <span aria-hidden="true">×</span> </button> <div role="alert" aria-live="polite"> This is an alert message. </div> """ ### 4.3 Focus Management **Do This:** * Ensure that all interactive elements are focusable and have a clear focus indicator. * Manage focus programmatically to ensure that the user's focus remains within a specific region of the page (e.g., a modal dialog). * Avoid trapping the user's focus within a component. **Don't Do This:** * Remove the default focus indicator from interactive elements. * Create focus traps that prevent users from navigating to other parts of the page. **Why:** Proper focus management ensures that users can navigate your application using the keyboard or other assistive technologies. **Example (Focus Trap - Avoid this! Illustrative of what *not* to do)** """javascript // WARNING: This demonstrates an anti-pattern (focus trap). Do not implement this directly. // AVOID: Focus trapping! This is used for demonstration purposes only and should not be implemented in production. // This code sets focus to the first focusable element inside a modal and prevents the user from tabbing out of it. This is **extremely** bad for accessibility. // DO NOT SHIP CODE LIKE THIS """ ### 4.4 Color Contrast **Do This:** * Ensure that the contrast ratio between text and background colors meets the WCAG 2.1 AA or AAA standards (a minimum of 4.5:1 for normal text and 3:1 for large text). * Use a color contrast checker to verify that your color combinations are accessible. * Provide a high-contrast theme for users with visual impairments. **Don't Do This:** * Use color combinations that are difficult to read or distinguish. * Rely solely on color to convey information. **Why:** Sufficient color contrast ensures that your content is readable for users with visual impairments. **Example:** Use a tool like [WebAIM's Contrast Checker](https://webaim.org/resources/contrastchecker/) to ensure your color choices meet accessibility standards. ## 5. Performance ### 5.1 Optimize CSS **Do This:** * Minify and compress your CSS files to reduce their size. * Remove unused CSS rules. * Use CSS selectors efficiently to avoid performance bottlenecks. * Leverage browser caching to reduce the number of requests for CSS files. **Don't Do This:** * Write overly complex CSS selectors that are difficult for the browser to parse. * Include large, unused CSS frameworks in your project. * Load CSS files synchronously in the "<head>" section of your HTML document. **Why:** Optimized CSS files improve page load times and reduce the amount of data that needs to be transferred over the network. ### 5.2 Lazy Loading **Do This:** * Lazy load images and other non-critical resources to improve initial page load time. * Use the "loading="lazy"" attribute for images that are below the fold. * Consider using a JavaScript library for more advanced lazy loading techniques. **Don't Do This:** * Lazy load critical resources that are needed for the initial rendering of the page. **Why:** Lazy loading reduces initial page load time by deferring the loading of non-critical resources until they are needed. **Example:** """html <img src="my-image.jpg" alt="My Image" loading="lazy"> """ ### 5.3 Code Splitting **Do This (when applicable):** * Split your JavaScript and CSS code into smaller chunks that can be loaded on demand. * Use dynamic imports to load modules only when they are needed. * Leverage your bundler's code splitting capabilities. **Don't Do This:** * Load all of your JavaScript and CSS code in a single large file. * Neglect to analyze your bundle size and identify opportunities for code splitting. **Why:** Code splitting reduces initial page load time by loading only the code that is needed for the current view. These coding standards will ensure codebases are easier to maintain and scale.
# Deployment and DevOps Standards for Bulma This document outlines the coding standards for Bulma projects, focusing specifically on deployment and DevOps practices. It is intended to guide developers in building robust, maintainable, and performant Bulma-based applications. This document is also designed to provide context for AI coding assistants, enabling them to generate code that adheres to these standards. ## 1. Build Processes and CI/CD for Bulma ### 1.1. Standard: Use a Robust Build System **Do This:** Use a modern build system such as Webpack, Parcel, or esbuild. These tools allow for efficient bundling, minification, and optimization of CSS and JavaScript. **Don't Do This:** Rely on manual concatenation and minification. This is error-prone and difficult to maintain as the project grows. **Why:** Automating the build process with a build system ensures consistency across environments, reduces the risk of human error, and significantly improves performance by optimizing assets. **Code Example (Webpack):** """javascript // webpack.config.js const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); module.exports = { entry: './src/js/app.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.scss$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', ], }, { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: 'bundle.css', }), ], optimization: { minimizer: [ '...', // Use TerserPlugin for JavaScript new CssMinimizerPlugin(), ], }, }; """ ### 1.2. Standard: Implement CSS Purging **Do This:** Integrate CSS purging tools like PurgeCSS or UnCSS to remove unused Bulma styles and custom CSS. **Don't Do This:** Include the entire Bulma CSS file without purging unused styles, especially for small projects where only a subset of Bulma's components are used. **Why:** Bulma provides a large number of CSS classes. Purging unused styles significantly reduces the size of the CSS file, resulting in faster page load times. This is particularly important for mobile users. **Code Example (PurgeCSS with Webpack):** """javascript // webpack.config.js const path = require('path'); const glob = require('glob'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const { PurgeCSSPlugin } = require('purgecss-webpack-plugin'); const PATHS = { src: path.join(__dirname, 'src') } module.exports = { entry: './src/js/app.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.scss$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', ], }, { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: 'bundle.css', }), new PurgeCSSPlugin({ paths: glob.sync("${PATHS.src}/**/*", { nodir: true }), // Consider using more explicit paths here safelist: { standard: [/^is-/, /^has-/, /^fa-/], // Bulma and FontAwesome modifiers deep: [/data-theme$/] }, }), ], optimization: { minimizer: [ '...', // Use TerserPlugin for JavaScript new CssMinimizerPlugin(), ], }, }; """ **Anti-Pattern:** Using a very broad selector for PurgeCSS paths (e.g., "/**/*") can inadvertently remove CSS classes that are dynamically added via JavaScript. Always refine paths to only include files that contain your HTML structure. ### 1.3. Standard: Implement Continuous Integration and Continuous Deployment (CI/CD) **Do This:** Set up a CI/CD pipeline using tools like GitHub Actions, GitLab CI, Jenkins, or CircleCI. The pipeline should automatically run tests, build the application, and deploy it to the target environment upon code changes. **Don't Do This:** Manually build and deploy the application. This is inefficient and increases the risk of introducing errors. **Why:** CI/CD automates the build, test, and deployment processes, ensuring rapid feedback, reducing errors, and enabling faster release cycles. **Code Example (GitHub Actions):** """yaml # .github/workflows/deploy.yml name: Deploy to Production on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18.x' - name: Install dependencies run: npm install - name: Build run: npm run build # Or yarn build, depending on your package manager - name: Deploy to Server uses: appleboy/scp-action@v0.1.10 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} source: dist/ target: /var/www/your-app/ - name: Restart Server uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | pm2 restart your-app # Assuming you're using PM2 """ **Explanation:** This GitHub Actions workflow is triggered on pushes to the "main" branch. It checks out the code, sets up Node.js, installs dependencies, builds the application (using a "build" script defined in "package.json"), deploys the contents of the "dist" directory to a server using "scp", and then restarts the application using "pm2". Secrets like server host, username, and SSH key are stored in GitHub's secrets management. ### 1.4. Standard: Version Control for Bulma Customizations **Do This:** Use a version control system (e.g., Git) to track all Bulma customizations, including custom themes, extensions, and overrides. **Don't Do This:** Modify Bulma's core files directly. Keep customizations separate to facilitate easier updates. **Why:** Version control allows you to track changes, collaborate effectively, and easily revert to previous versions if necessary. Separating customizations avoids conflicts when upgrading Bulma. **Example:** Maintain a separate "src/sass/custom.scss" file to contain all your overrides, and import the Bulma library at the top: """scss // src/sass/custom.scss @import "~bulma/sass/bulma"; // Your customizations $primary: #ff0000; .my-custom-class { color: $primary; } """ ### 1.5. Standard: Automate Image Optimization **Do This:** Integrate image optimization tools into your build process. Tools like "imagemin-webpack-plugin" will automatically compress images during your build. Consider using modern image formats like WebP. **Don't Do This:** Deploy unoptimized images. Ensure that all images are properly compressed and sized for their intended display. **Why:** Optimized images drastically reduce page load times and improve the user experience, especially on mobile devices. **Code Example (imagemin-webpack-plugin):** """javascript // webpack.config.js const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); module.exports = { // ... other webpack configuration optimization: { minimizer: [ // ... other minimizers new ImageMinimizerPlugin({ minimizer: { implementation: ImageMinimizerPlugin.imageminMinify, options: { plugins: [ ["gifsicle", { interlaced: true }], ["jpegtran", { progressive: true }], ["optipng", { optimizationLevel: 5 }], [ "svgo", { plugins: [ { name: "preset-default", params: { overrides: { removeViewBox: false, addAttributesToSVGElement: { params: { attributes: [{ xmlns: "http://www.w3.org/2000/svg" }], }, }, }, }, }, ], }, ], ], }, }, }), ], }, plugins: [ //... other plugins ] }; """ ## 2. Production Considerations for Bulma ### 2.1. Standard: Enable Caching **Do This:** Configure your web server (e.g., Nginx, Apache, or CDN) to properly cache static assets, including CSS, JavaScript, images, and fonts. Use appropriate "Cache-Control" headers to control caching behavior. **Don't Do This:** Disable caching or use overly short cache durations. This forces browsers to re-download assets on every page load, significantly increasing latency. **Why:** Caching reduces server load and improves performance by allowing browsers to store static assets locally. **Code Example (Nginx Configuration):** """nginx location ~* \.(?:css|js|json|svg|eot|ttf|woff|woff2)$ { expires 30d; add_header Cache-Control "public, max-age=2592000"; } location ~* \.(?:png|jpg|jpeg|gif)$ { expires 7d; add_header Cache-Control "public, max-age=604800"; } """ **Explanation:** This Nginx configuration sets a 30-day cache expiration for CSS, JavaScript, JSON, SVG, and font files, and a 7-day expiration for image files. The "Cache-Control" header instructs browsers and CDNs to cache these assets publicly. ### 2.2. Standard: Utilize a Content Delivery Network (CDN) **Do This:** Host static assets (CSS, JavaScript, images, fonts) on a CDN to distribute content geographically closer to users. **Don't Do This:** Serve all assets from a single server, especially for applications with a global audience. **Why:** CDNs improve performance by reducing latency and providing highly available content delivery. **Example:** Services like Cloudflare, AWS CloudFront, or Google Cloud CDN can be used to host your Bulma-based application's static assets. ### 2.3. Standard: Monitor Application Performance **Do This:** Implement real-time monitoring of application performance using tools like Google Analytics, New Relic, or Sentry. Monitor key metrics such as page load times, error rates, and API response times. Also, consider using Lighthouse or PageSpeed Insights to get reports and suggestions. **Don't Do This:** Neglect performance monitoring. Proactively identify and address performance bottlenecks. **Why:** Monitoring allows you to identify and resolve performance issues quickly, ensuring a positive user experience. ### 2.4. Standard: Implement Error Tracking **Do This:** Integrate an error-tracking tool like Sentry or Bugsnag to capture and report JavaScript errors and server-side exceptions that may occur in production. **Don't Do This:** Rely solely on user reports for error detection. Proactively monitor and address errors to improve application stability. **Why:** Error tracking helps you identify and fix errors that users may encounter, improving application stability and reducing user frustration. ### 2.5. Standard: Security Hardening **Do This:** Implement security best practices, including: * Using HTTPS to encrypt all traffic. * Setting appropriate HTTP security headers (e.g., Content-Security-Policy, X-Frame-Options, Strict-Transport-Security). * Protecting against Cross-Site Scripting (XSS) attacks by sanitizing user input and encoding output. * Regularly updating dependencies to patch security vulnerabilities. * Auditing your Bulma customizations for potential security flaws. **Don't Do This:** Ignore security considerations. A security breach can have serious consequences for your application and users. **Why:** Security hardening protects your application and users from various attacks. **Example (Content Security Policy):** Setting a restrictive CSP can prevent many XSS attacks. The exact policy will depend on your applications needs. ### 2.6. Standard: Feature Flags and Rollouts **Do This:** Consider using feature flags to gradually roll out new features to a subset of users. This allows you to test new features in a production environment with minimal risk. **Don't Do This:** Deploy large, untested features directly to all users. **Why:** Feature flags reduce the risk associated with deploying new features by allowing you to test them with a smaller audience and quickly revert changes if necessary. ### 2.7. Bulma-Specific Considerations for Deployment * **Custom Themes:** When deploying custom Bulma themes, ensure that the custom theme files are loaded *after* the core Bulma CSS. CSS specificity and cascade rules apply! * **JavaScript Dependencies**: Ensure all Bulma JavaScript dependencies are included and loaded correctly, particularly when using Bulma extensions or custom components that rely on JavaScript. * **Accessibility**: Review your application's accessibility after deployment. Use tools like WAVE to identify and fix accessibility issues. Ensure color contrast ratios are sufficient and that all interactive elements are properly labeled. By following these Deployment and DevOps standards, developers can build and deploy robust, performant, and secure Bulma applications. These standards are intended to promote consistency, reduce errors, and enable faster release cycles. They also provide a clear guide for AI coding assistants, helping them to generate code that aligns with these best practices.
# Tooling and Ecosystem Standards for Bulma This document outlines the recommended tools, libraries, extensions, and practices for developing with Bulma effectively and efficiently. These standards are designed to promote maintainability, performance, and security within your Bulma projects. They also provide context to AI coding assistants on the proper methods of usage, enabling them to generate helpful and effective code. ## 1. Build Tools and Package Management ### 1.1. Package Manager Selection: npm or Yarn **Standard:** Use either npm or Yarn as your package manager. Yarn is often preferred for its speed and deterministic dependency resolution (using yarn.lock), while npm is widely adopted and integrated with Node.js. **Do This:** * Choose either npm or Yarn at the project's inception and consistently use it. * Include "package-lock.json" (for npm) or "yarn.lock" (for Yarn) in your Git repository to ensure consistent dependency versions across environments. **Don't Do This:** * Mix npm and Yarn in the same project. * Forget to commit the lock file to your repository. **Why:** Consistency in package management reduces dependency conflicts and ensures that all developers and environments use the same versions of packages, preventing unexpected behavior. **Example (npm):** """bash npm install bulma npm install node-sass --save-dev """ **Example (Yarn):** """bash yarn add bulma yarn add node-sass --dev """ ### 1.2. Task Runners and Build Systems: npm scripts, Gulp, or Webpack **Standard:** Use npm scripts, Gulp, or Webpack for build automation, Sass compilation, and other development tasks. Webpack, with its module bundling capabilities, is highly recommended for complex projects that utilize modern JavaScript modules or assets. Gulp is a good choice for simpler task automation workflows. npm scripts offer a lightweight and dependency-free approach. **Do This:** * Define build, test, and other utility commands in your "package.json" using npm scripts. * Use Gulp for more complex task automation, such as file minification and image optimization. * Use Webpack for bundling assets, especially when dealing with JavaScript modules and dependencies. **Don't Do This:** * Manually compile Sass or perform other build steps. * Overcomplicate build processes with unnecessary dependencies. **Why:** Automation streamlines development, reduces errors, and ensures consistent build processes. **Example (npm scripts in "package.json"):** """json { "scripts": { "build:sass": "node-sass sass/main.scss css/style.css", "watch:sass": "node-sass sass/main.scss css/style.css --watch", "start": "npm run watch:sass" }, "devDependencies": { "node-sass": "^7.0.0" } } """ **Example (Gulp):** """javascript // gulpfile.js const gulp = require('gulp'); const sass = require('gulp-sass')(require('node-sass')); const autoprefixer = require('gulp-autoprefixer'); const cleanCSS = require('gulp-clean-css'); function compileSass() { return gulp.src('sass/main.scss') .pipe(sass().on('error', sass.logError)) .pipe(autoprefixer({ cascade: false })) .pipe(cleanCSS({compatibility: 'ie8'})) .pipe(gulp.dest('css')); } function watch() { gulp.watch('sass/**/*.scss', compileSass); } exports.compileSass = compileSass; exports.watch = watch; exports.default = gulp.series(compileSass, watch); """ **Example (Webpack):** """javascript // webpack.config.js const path = require('path'); module.exports = { entry: './js/app.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [ { test: /\.scss$/, use: [ 'style-loader', // Creates "style" nodes from JS strings 'css-loader', // Translates CSS into CommonJS 'sass-loader' // Compiles Sass to CSS ] } ] } }; """ ### 1.3. Linting and Formatting: Stylelint and Prettier **Standard:** Use Stylelint for linting and Prettier for code formatting. Configure them to enforce consistent styling and formatting across your codebase. **Do This:** * Install Stylelint and Prettier as development dependencies. * Configure Stylelint with rules specific to Bulma and Sass standards. * Configure Prettier with consistent settings for indentation, line length, and other formatting options. * Integrate Stylelint and Prettier into your editor or IDE for real-time feedback. * Use Husky or similar tools to run linters and formatters before committing code. **Don't Do This:** * Ignore linting and formatting warnings. * Use inconsistent styling or formatting across files. **Why:** Consistent styling and formatting improve code readability and reduce cognitive load, making it easier for developers to understand and maintain the codebase. **Example (.stylelintrc.json):** """json { "extends": "stylelint-config-standard-scss", "rules": { "selector-class-pattern": null, // Allow Bulma's class naming convention "at-rule-no-unknown": null, // To avoid false positives with Sass directives "scss/at-rule-no-unknown": true } } """ **Example (.prettierrc.json):** """json { "semi": false, "singleQuote": true, "trailingComma": "es5", "tabWidth": 2 } """ **Example (Husky pre-commit hook):** """json // package.json { "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{scss,css}": "stylelint --fix", "*.{js,json}": "prettier --write" } } """ ## 2. Bulma Extensions and Add-ons ### 2.1. Officially Supported Extensions **Standard:** Prioritize officially supported or widely used and maintained Bulma extensions. Check their documentation and contribution history when choosing which extensions to use. **Do This:** * Research extensions before using them in your project. * Ensure the extension is actively maintained and compatible with your Bulma version. **Don't Do This:** * Use unmaintained or abandoned extensions, as they might introduce security vulnerabilities or compatibility issues. **Why:** Stable and well-maintained extensions enhance Bulma's capabilities, providing more components and utilities without compromising project stability. ### 2.2. Bulma Customization Libraries **Standard:** Favor libraries that enhance Bulma itself through Sass variables or component composition rather than extensions requiring extensive JavaScript or CSS overrides. **Do This:** * Look for libraries offering Sass mixins or variables to customize Bulma's appearance. * Ensure that additional CSS integrates seamessly and follows Bulma's standards. **Don't Do This:** * Implement libraries that heavily change the core styling or markup, as this reduces the benefit of Bulma's pre-defined styles. **Why:** Simple customization libraries maintain Bulma's core structure, improving consistency and upgradeability. ### 2.3. JavaScript Integration **Standard:** When JavaScript integration is required, prefer native JavaScript over jQuery whenever possible. Use lightweight JavaScript libraries or frameworks strategically. **Do This:** * Use native JavaScript for DOM manipulation, event handling, and AJAX requests. * Consider using a lightweight framework when more advanced UI interactions are required. **Don't Do This:** * Rely heavily on jQuery for basic DOM manipulation tasks. * Introduce unnecessary dependencies for simple interactivity. **Why:** Native JavaScript is more performant and reduces the overall project size. Using lightweight libraries minimizes dependency bloat. **Example (Native JavaScript Toggle):** """html <button id="toggleButton">Toggle</button> <div id="content" class="is-hidden">Content to toggle</div> <script> const toggleButton = document.getElementById('toggleButton'); const content = document.getElementById('content'); toggleButton.addEventListener('click', () => { content.classList.toggle('is-hidden'); }); </script> """ ### 2.4. Accessibility Integration **Standard**: Ensure that extensions and integrations comply with accessibility (ARIA) standards. When integrating Javascript components, ensure these additions provide proper ARIA attributes and keyboard navigation. **Do This:** * Test any JavaScript-enhanced Bulma components for keyboard accessibility and screen reader compatibility. * Verify sufficient color contrast between text and background colors. **Don't Do This:** * Add extensions or JS components that break accessibility. **Why:** Accessibility ensures your Bulma-based applications are usable by everyone, including people with disabilities. ## 3. Debugging and Development Tools ### 3.1. Browser Developer Tools **Standard:** Utilize browser developer tools (Chrome DevTools, Firefox Developer Tools) for debugging CSS and JavaScript. **Do This:** * Use the "Inspect" tool to examine HTML elements and their applied CSS styles. * Use the "Console" to log messages and debug JavaScript code. * Use the "Network" tab to analyze network requests and identify performance bottlenecks. **Don't Do This:** * Rely solely on "console.log" statements for debugging. * Ignore browser warnings and errors. **Why:** Browser developer tools provide powerful debugging capabilities and performance insights, making it easier to diagnose and fix issues. ### 3.2. Responsive Design Testing **Standard:** Test your Bulma layouts on various screen sizes and devices using browser developer tools or dedicated testing tools. **Do This:** * Use the responsive design mode in browser developer tools to simulate different screen sizes and orientations. * Test on physical devices to ensure proper rendering and usability. * Consider using cross-browser testing tools like BrowserStack or Sauce Labs. **Don't Do This:** * Assume your layout will work perfectly on all devices without proper testing. **Why:** Responsive design testing ensures that your application provides a consistent and user-friendly experience across all devices. ### 3.3. Performance Analysis **Standard:** Use performance analysis tools to identify and address potential performance bottlenecks. **Do This:** * Use browser developer tools (e.g., Chrome DevTools' "Performance" tab) to profile your application's performance. * Identify slow-loading resources, inefficient JavaScript code, and excessive DOM manipulation. * Optimize images and other assets to reduce file sizes. **Don't Do This:** * Ignore performance issues until they become critical. **Why:** Performance analysis enables you to optimize your application for speed and responsiveness, improving the user experience. ## 4. Version Control and Collaboration ### 4.1. Git and GitHub/GitLab/Bitbucket **Standard:** Use Git for version control and a platform like GitHub, GitLab, or Bitbucket for collaboration. **Do This:** * Commit code frequently with clear and concise commit messages. * Use branching strategies (e.g., Gitflow) to manage feature development and releases. * Use pull requests for code review and collaboration. **Don't Do This:** * Commit large changes without proper testing. * Push code directly to the main branch. * Ignore code review feedback. **Why:** Version control enables you to track changes to your codebase, collaborate effectively with other developers, and revert to previous versions if necessary. ### 4.2. Code Reviews **Standard:** Conduct thorough code reviews before merging changes into the main branch. **Do This:** * Focus on code quality, maintainability, security, and performance during code reviews. * Provide constructive feedback and suggest improvements. * Ensure that all code adheres to these coding standards. **Don't Do This:** * Skip code reviews. * Approve code without thoroughly understanding it. **Why:** Code reviews help identify potential issues early, improve code quality, and promote knowledge sharing among team members. ## 5. Documentation Tools ### 5.1. Project README **Standard:** Maintain a comprehensive README file for your Bulma project. **Do This:** * Include a clear description of the project's purpose and features. * Provide instructions on how to set up the development environment, install dependencies, and run the application. * Document any project-specific coding standards or conventions. **Don't Do This:** * Leave the README file incomplete or outdated. **Why:** A well-maintained README file makes it easier for new developers to understand the project and get started quickly. ### 5.2. Inline Code Documentation **Standard:** Document your code using comments and documentation generators (e.g., JSDoc for JavaScript). Provide semantic HTML markup for better code understanding. **Do This:** * Use comments to explain complex logic, non-obvious code, and important design decisions. * Use documentation generators to create API documentation from your code comments. **Don't Do This:** * Over-comment code with obvious explanations. * Fail to document important code sections. **Why:** Code documentation makes it easier for developers to understand and maintain the codebase, especially in complex projects. By following these tooling and ecosystem standards, you can create robust, maintainable, and performant Bulma-based applications. This guidance, combined with AI coding assistants trained on these principles, will lead to significant improvements in code quality and development efficiency.
# Core Architecture Standards for Bulma This document defines the core architecture standards for developing maintainable, performant, and scalable web applications with the Bulma CSS framework. It focuses on architectural patterns, project structure, and organization principles that should be adhered to by all developers. These standards aim to promote consistency, readability, and long-term maintainability of Bulma-based projects. ## 1. Project Structure and Organization A well-defined project structure is crucial for managing complexity and ensuring that the codebase remains organized as the project grows. ### 1.1. Directory Structure **Do This:** * Adopt a modular and component-based project structure. Organize your files and dependencies into logical modules or feature areas. * Maintain clear separation of concerns: HTML templates, CSS/Sass styles, and JavaScript logic should reside in distinct directories. * Use a "src" directory to house all source code, separating it from build artifacts and configuration files. **Don't Do This:** * Avoid a flat directory structure where all files are placed in a single directory. * Don't mix HTML, CSS/Sass, and JavaScript files within the same directory unless there is a specific valid reason and it concerns a single component. **Why:** * **Maintainability:** A modular structure makes it easier to locate, understand, and modify specific parts of the application. * **Scalability:** Clear separation of concerns allows for independent scaling and modular testing of individual components of the application. * **Collaboration:** A standardized directory structure facilitates collaboration among developers by providing a common ground for finding and contributing code. **Example:** """ project-root/ ├── src/ │ ├── assets/ # Static assets (images, fonts, etc.) │ ├── components/ # Reusable Bulma components │ │ ├── navbar/ # Example component: Navbar │ │ │ ├── navbar.html │ │ │ ├── navbar.scss │ │ │ └── navbar.js │ │ ├── button/ # Example Component: Button │ │ │ ├── button.html │ │ │ ├── button.scss │ │ │ └── button.js │ ├── styles/ # Global stylesheets and Bulma customizations │ │ ├── main.scss # Main stylesheet importing all modules │ │ └── _variables.scss # Custom Bulma variables │ ├── scripts/ # Main JavaScript files │ │ └── main.js │ ├── index.html # Main HTML file │ └── app.js # Main app javascript file ├── dist/ # Build artifacts ├── node_modules/ # Node modules ├── package.json ├── webpack.config.js └── README.md """ ### 1.2. Naming Conventions **Do This:** * Use consistent and descriptive names for files, directories, and variables. File names should clearly indicate the component or module they contain. * Adopt a naming convention (e.g., BEM) for CSS classes to improve readability and avoid naming conflicts. * Use lowercase and hyphens (-) for CSS class names (e.g., "navbar-item", "button-primary"). * Use camelCase for JavaScript variables and functions (e.g., "initNavbar", "handleButtonClick"). **Don't Do This:** * Avoid cryptic or ambiguous names that don't convey the purpose of the element. * Don't use inconsistent naming conventions across the project. * Don't use underscores (_) in CSS class names. **Why:** * **Readability:** Consistent naming conventions make the codebase easier to read and understand. * **Maintainability:** Descriptive names make it easier to locate and modify specific elements in the code. * **Collaboration:** Standardized naming conventions ensure that all developers use the same language when referring to elements in the codebase. **Example:** """html <!-- Component: Button --> <button class="button button-primary">Click me</button> """ """scss /* styles/components/_button.scss */ .button { padding: 10px 20px; border: none; cursor: pointer; &.button-primary { background-color: blue; color: white; } } """ """javascript // scripts/components/button.js function handleButtonClick() { console.log('Button clicked!'); } const primaryButtons = document.querySelectorAll(".button-primary"); primaryButtons.forEach(button => { button.addEventListener('click', handleButtonClick); }); """ ## 2. Bulma Customization and Extension Bulma is designed to be easily customizable and extensible. Understanding how to properly modify Bulma's default styles and components is critical for building consistent and maintainable applications. ### 2.1. Using Bulma Variables **Do This:** * Leverage Bulma's Sass variables to customize the framework's appearance (colors, fonts, spacing, etc). * Create a dedicated "_variables.scss" file in your "styles" directory to override the default variables. * Import your "_variables.scss" file *before* importing the Bulma stylesheet. **Don't Do This:** * Avoid directly modifying the Bulma source files. Customizations should be done through variable overrides. * Don't hardcode values in your CSS that conflict with Bulma's design system. **Why:** * **Maintainability:** Variable overrides allow you to update the look and feel of your application without modifying the Bulma source code. This makes it easier to upgrade to newer versions of Bulma. * **Consistency:** Using variables ensures that styles are consistent across the application and follows the design system. * **Theming:** Variable overrides allow you to easily create different themes for your application. **Example:** """scss /* styles/_variables.scss */ $primary: #209CEE; $secondary: #7949d5; $family-sans-serif: "Nunito", sans-serif; """ """scss /* styles/main.scss */ @import "variables"; // Import custom variables BEFORE bulma @import "~bulma/sass/bulma"; """ ### 2.2. Extending Bulma with Custom Components **Do This:** * Create new components in separate files within the "components" directory. * Use Bulma's existing classes as a foundation for your custom components. * Leverage Sass mixins and functions to generate consistent styles. **Don't Do This:** * Don't apply inline styles directly to HTML elements unless absolutely necessary. * Avoid overwriting Bulma's core styles unless there is a compelling reason to do so. **Why:** * **Reusability:** Custom components promote code reuse. * **Consistency:** Leverages Bulma's styles for a consistent look and feel. * **Maintainability:** Easier to update and maintain custom components when they are separate and well-defined. **Example:** """scss /* styles/components/_custom-card.scss */ .custom-card { @extend .card; // Inheriting Bulma's card styles border-radius: 10px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); .card-header { background-color: $primary; // Use custom Bulma variable color: white; font-weight: bold; } .card-content { padding: 1.5rem; } } """ """html <!-- components/custom-card.html --> <div class="custom-card"> <header class="card-header"> <p class="card-header-title"> Custom Card Title </p> </header> <div class="card-content"> <p>This is the content of the card. Uses a custom Bulma variable.</p> </div> </div> """ ### 2.3. Using Bulma Modifiers and Helpers **Do This:** * Understand and utilize Bulma's modifier classes (e.g., ".is-primary", ".is-small") and helper classes (e.g., ".has-text-centered", ".is-hidden") to control element appearance and behavior. * Use modifier classes to create variations of standard Bulma components (e.g., a primary-colored button). Use helper classes for utility purposes like text alignment and visibility control. **Don't Do This:** * Don't create custom CSS classes that duplicate the functionality of Bulma's modifier and helper classes. * Avoid overusing custom styles when Bulma provides built-in options. **Why:** * **Efficiency:** Reduces the amount of custom CSS required. * **Consistency:** Ensures that styles are consistent with Bulma's design system and provides a uniform look across the application. * **Readability:** Makes the HTML code more concise and easier to understand. **Example:** """html <button class="button is-primary is-small">Submit</button> <p class="has-text-centered">This text is centered.</p> """ ## 3. JavaScript Integration Bulma is primarily a CSS framework, but it often requires JavaScript for interactive components. ### 3.1. Decoupling JavaScript from HTML **Do This:** * Separate JavaScript logic from HTML markup. Place JavaScript code in separate ".js" files and use event listeners to attach behavior to DOM elements. * Use data attributes ("data-*") to store component-specific data within HTML elements. **Don't Do This:** * Avoid inline JavaScript (e.g., "<button onclick="myFunction()">") as it pollutes the HTML and makes it harder to maintain. * Don't directly manipulate the DOM without proper event handling and error checking. **Why:** * **Maintainability:** Separating JavaScript makes the code easier to read, understand, and debug. * **Reusability:** JavaScript code can be reused across multiple components. * **Testability:** Separated JavaScript logic is easier to test. **Example:** """html <!-- components/navbar.html --> <nav class="navbar" role="navigation" aria-label="main navigation"> <div class="navbar-brand"> <a class="navbar-item" href="https://bulma.io"> <img src="https://bulma.io/images/bulma-logo.png" width="112" height="28"> </a> <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample"> <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> </a> </div> <div id="navbarBasicExample" class="navbar-menu"> <div class="navbar-start"> <a class="navbar-item"> Home </a> <a class="navbar-item"> Documentation </a> </div> </div> </nav> """ """javascript // scripts/components/navbar.js document.addEventListener('DOMContentLoaded', () => { // Get all "navbar-burger" elements const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); // Add a click event on each of them $navbarBurgers.forEach( el => { el.addEventListener('click', () => { // Get the "data-target" attribute from the "navbar-burger" element const target = el.dataset.target; const $target = document.getElementById(target); // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" el.classList.toggle('is-active'); $target.classList.toggle('is-active'); }); }); }); """ ### 3.2. Using a JavaScript Framework or Library **Do This:** * Consider using a JavaScript framework or library (e.g., React, Vue.js, Angular) to manage Bulma components and create complex user interfaces. * Choose a framework that aligns with the complexity of your project and the skill set of your team. **Don't Do This:** * Avoid using a framework if it's not necessary for the project. * Don't over-engineer simple interactions with complex JavaScript frameworks. Bulma's simplicity should be complemented, not complicated. **Why:** * **Componentization:** JavaScript frameworks provide a structured way to organize components and manage their state. * **Data Binding:** Simplifies the process of updating the UI in response to data changes. * **Rich Interactions:** Enables the creation of complex user interfaces and interactive components. **Example (Vue.js):** """vue // Navbar.vue <template> <nav class="navbar" role="navigation" aria-label="main navigation"> <div class="navbar-brand"> <a class="navbar-item" href="https://bulma.io"> <img src="https://bulma.io/images/bulma-logo.png" width="112" height="28"> </a> <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample" @click="toggleMenu" > <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> </a> </div> <div id="navbarBasicExample" class="navbar-menu" :class="{ 'is-active': isActive }"> <div class="navbar-start"> <a class="navbar-item"> Home </a> <a class="navbar-item"> Documentation </a> </div> </div> </nav> </template> <script> export default { data() { return { isActive: false }; }, methods: { toggleMenu() { this.isActive = !this.isActive; } } }; </script> """ ## 4. Performance Optimization Optimizing the performance of Bulma-based applications is essential for providing a smooth user experience. ### 4.1. Minifying and Compressing Assets **Do This:** * Minify CSS and JavaScript files to reduce their size. Use tools like CSSNano or Terser to remove unnecessary characters and whitespace from the code. * Compress assets (images, fonts, etc.) to reduce their download time. * Enable Gzip compression on your web server to further reduce the size of transferred assets. **Don't Do This:** * Don't deploy unminified and uncompressed assets to production. * Don't use overly large images or unoptimized fonts. **Why:** * **Faster Load Times:** Reduces the amount of data that needs to be downloaded, resulting in faster page load times. * **Improved User Experience:** Faster loading websites provide a better user experience. **Example (Webpack Configuration):** """javascript const TerserPlugin = require("terser-webpack-plugin"); const CSSMinimizerPlugin = require("css-minimizer-webpack-plugin"); module.exports = { //... other config options optimization: { minimize: true, minimizer: [ new TerserPlugin(), new CSSMinimizerPlugin(), ], }, }; """ ### 4.2. Code Splitting **Do This:** * Implement code splitting to break down JavaScript code into smaller chunks that can be loaded on demand. * Use dynamic imports to load modules only when they are needed. **Don't Do This:** * Don't load all JavaScript code upfront, especially for large applications with many components. * Avoid creating large monolithic JavaScript bundles. **Why:** * **Improved Initial Load Time:** Loads only the necessary code upfront, reducing initial load time. * **Reduced Bandwidth Consumption:** Only downloads code that is actually used. * **Better User Experience:** Results in a faster and more responsive user experience. **Example:** """javascript // scripts/main.js async function loadComponent() { const { MyComponent } = await import('./components/my-component'); // Use MyComponent } loadComponent(); """ ### 4.3. Lazy Loading Images **Do This:** * Implement lazy loading for images to defer the loading of images that are not initially visible in the viewport. * Use the "loading="lazy"" attribute on "<img>" tags to enable native lazy loading. **Don't Do This:** * Don't load all images upfront, especially for pages with many images. * Avoid using very large images that are not properly optimized for the web. **Why:** * **Improved Initial Load Time:** Loads only the images that are visible in the viewport, reducing initial load time. * **Reduced Bandwidth Consumption:** Only downloads images that are actually needed. * **Better User Experience:** Results in a faster and more responsive user experience. **Example:** """html <img src="image.jpg" loading="lazy" alt="My Image"> """ ## 5. Accessibility (A11y) Accessibility is a crucial aspect of modern web development. Ensure your Bulma-based applications are usable by people with disabilities. ### 5.1. Semantic HTML **Do This:** * Use semantic HTML elements (e.g., "<nav>", "<article>", "<aside>", "<footer>") to structure the content of your pages. * Use proper heading levels ("<h1>" - "<h6>") to create a logical document outline. * Use ARIA attributes to enhance the accessibility of interactive components. **Don't Do This:** * Avoid using generic "<div>" and "<span>" elements for everything. * Don't rely solely on CSS for conveying meaning or structure. **Why:** * **Improved Screen Reader Compatibility:** Screen readers rely on semantic HTML to understand the structure and content of a page. * **Better SEO:** Search engines also use semantic HTML to understand the content of a page. * **Enhanced Usability:** Semantic HTML makes the code more readable and maintainable. **Example:** """html <nav aria-label="Main Navigation"> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> </nav> <article> <h1>Article Title</h1> <p>Article content...</p> </article> """ ### 5.2. ARIA Attributes **Do This:** * Use ARIA attributes to provide additional information to assistive technologies about the role, state, and properties of interactive elements. * Use "aria-label" to provide a descriptive label for elements that don't have visible text labels. * Use "aria-live" to announce dynamic content updates to screen readers. **Don't Do This:** * Don't overuse ARIA attributes. Use semantic HTML whenever possible. * Don't provide conflicting or inaccurate information with ARIA attributes. "role=button" on an "<a>" tag that doesn't actually act like a button, for instance. **Why:** * **Improved Accessibility:** ARIA attributes fill the gaps in native HTML and provide additional information to assistive technologies. * **Enhanced User Experience:** Makes the application more usable for people with disabilities. **Example:** """html <button aria-label="Close" onclick="closeModal()"> <span aria-hidden="true">×</span> </button> <div aria-live="polite"> <!-- Dynamic content updates will be announced --> </div> """ ### 5.3. Color Contrast **Do This:** * Ensure sufficient color contrast between text and background colors to meet WCAG guidelines. * Use a color contrast checker to verify that your color combinations meet accessibility standards. **Don't Do This:** * Don't use low-contrast color combinations that are difficult to read for people with visual impairments. Always test! * Avoid relying solely on color to convey important information. Colors can not be the only indicator, as colorblind users will not be able to benefit. **Why:** * **Improved Readability:** High color contrast makes the text easier to read for everyone. * **Accessibility for Visual Impairments:** Ensures that the application is usable for people with low vision. * **Compliance:** Meeting WCAG guidelines is often a legal requirement. **Example:** """scss /* styles/_variables.scss */ $primary: #209CEE; //Primary Color $primary-invert: #fff; //Invert Color """ ## 6. Security Best Practices Security is paramount in web development. Adopt these practices to protect your Bulma applications. ### 6.1. Input Validation **Do This:** * Validate all user inputs on both the client and server sides to prevent malicious data from being processed. * Sanitize user inputs to remove potentially harmful characters or code. **Don't Do This:** * Don't trust user inputs without validation. Assume all user inputs are potentially malicious. * Don't rely solely on client-side validation, as it can be easily bypassed. **Why:** * **Prevention of Cross-Site Scripting (XSS) Attacks:** Input validation can prevent attackers from injecting malicious scripts into your application. * **Prevention of SQL Injection Attacks:** Input validation can prevent attackers from manipulating database queries. * **Data Integrity:** Ensures that only valid data is stored in your database. ### 6.2. Cross-Site Scripting (XSS) Protection **Do This:** * Use a Content Security Policy (CSP) to control the sources from which the browser is allowed to load resources. * Escape user-generated content when displaying it on the page to prevent XSS attacks. * Avoid using "eval()" or other methods that execute arbitrary JavaScript code. **Don't Do This:** * Don't allow users to inject arbitrary HTML or JavaScript code into your application. * Don't disable XSS protection features in your web server or framework. **Why:** * **Protection Against XSS Attacks:** CSP and output escaping can prevent attackers from injecting malicious scripts into your application. * **Enhanced Security:** Reduces the attack surface of your application. ### 6.3. Dependencies Management **Do This:** * Keep your Bulma and other dependencies up to date to patch security vulnerabilities. * Use a dependency management tool (e.g., npm, yarn) to manage your project's dependencies. * Regularly audit your dependencies for known vulnerabilities. **Don't Do This:** * Don't use outdated versions of Bulma or other dependencies. * Don't install dependencies from untrusted sources. **Why:** * **Security Vulnerability Patching:** Updating dependencies ensures that security vulnerabilities are patched. * **Improved Stability:** Newer versions of dependencies often include bug fixes and performance improvements. * **Reduced Risk of Attacks:** Using up-to-date dependencies reduces the attack surface of your application. ## 7. Testing Thoroughly test your Bulma-based applications to ensure they function properly and provide a good user experience. ### 7.1. Unit Testing **Do This:** * Write unit tests for individual components and functions. * Use a testing framework (e.g., Jest, Mocha) to automate the testing process. * Aim for high code coverage to ensure that most of the code is tested. **Don't Do This:** * Don't skip unit testing, especially for critical components and functions. * Don't write tests that are too tightly coupled to the implementation details. **Why:** * **Early Bug Detection:** Unit tests can detect bugs early in the development process. * **Code Quality Assurance:** Ensures that individual components and functions work as expected. * **Refactoring Safety:** Provides confidence when refactoring code. ### 7.2. End-to-End Testing **Do This:** * Write end-to-end tests to simulate user interactions with the application. * Use a testing framework (e.g., Cypress, Selenium) to automate the testing process. * Test critical user flows to ensure that the application functions correctly in a real-world environment. **Don't Do This:** * Don't rely solely on manual testing. * Don't neglect end-to-end testing, especially for complex applications with many user interactions. **Why:** * **Real-World Testing:** Simulates user interactions and tests the application in a real-world environment. * **Detection of Integration Issues:** Identifies issues that may arise when different components of the application interact. * **User Experience Assurance:** Ensures that the application provides a good user experience. ### 7.3. Accessibility Testing **Do This:** * Test your applications for accessibility issues using automated tools and manual reviews. * Use accessibility checkers to verify that your color combinations meet WCAG guidelines. * Use screen readers to test the accessibility of your applications for people with visual impairments. **Don't Do This:** * Don't ignore accessibility testing. * Don't rely solely on automated tools for accessibility testing. **Why:** * **Accessibility Compliance:** Ensures that the application meets accessibility standards. * **Improved Usability:** Makes the application more usable for people with disabilities. * **Ethical Responsibility:** Accessibility is often a legal and ethical requirement.