Share React Components Across Projects with Git Submodules
Reusing components and code is a fundamental aspect of React projects, offering developers the ability to write code once and leverage it across different parts of an application. But as projects evolve and grow, the need of reusing components and functionality across various React projects becomes increasingly apparent.
There are a few ways and platforms that offer code sharing across projects (which I will mention later), however, in this post, we explore a simple concept of code-sharing between different React projects in a more private way by using Git submodules without relying on third-party platforms or tools.
Git submodules are a feature in Git that allows you to integrate external repositories as dependencies within your project, maintaining their independence and version control.
Section 1: Setting up Git Submodules for Component Sharing
First, we'll need three different remote Git repositories. One will contain the code that we need to reuse - in this case a simple Button component, and the other two projects will be simple React apps with the Button from the shared repository.
Create three empty remote repositories using the version control tool of your choice (for example Github) named: first-app, second-app and component-library.
Then, clone the first-app and second-app locally and in each of its root directory run:
git submodule add <repository_url> <submodule_path>
where repository_url is the url of the repository you created that will contain the shared Button component, in this case component-library and submodule_path is the name of the directory that will contain the component-library repository, for this example, let's name it components.
Section 2: Creating the shared component
Next clone the component-library repository and in the root directory of the component library add a new folder button with index.js file for the component code and button.css for the styling:
// index.js
import './button.css';
function Button() {
return (
<button className="button">
This is a Button component from my
Component library
</button>
);
}
export default Button;
// button.css
.button {
background-color: #E8AA42;
padding: 10px;
border: 0;
border-radius: 5px;
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
Then, commit and push the changes to the remote:
git add .
git commit -m "create button component"
git push
Section 3: Using the Shared Components in the other React Project
Now that we built the shared component, let's use it in two projects. First, we need to create the apps. For this simple idea, we'll demonstrate how to set up projects using different tools: Create React App, Vite, and Next.js.
To create the first project, clone the first-app repository locally and navigate to its root directory.
- Using Create React App:
To create the first project using Create React App, in the project directory run:
npx create-react-app .
- Using Vite:
If you prefer to use Vite, in the project directory run the following command:
npm create vite@latest . --template react
- Using Next.js:
For a Next.js app, in the project directory run the following command:
npx create-next-app .
If you wish to use a different tool to build the app, please refer to their official documentation to get specific instructions on setting up your project.
Since we already setup the submodule, we need to update it to get the latest changes we did.
cd src/components
git pull
To use the shared component, open the App.js file and import the Button component from the src/components/button folder.
Start the application with npm run start and test the changes! You should be able to see the button component. Repeat the same process with the second-app repository.
Section 4: Managing Changes and Updates
Changes and updates can be done from any repository that uses the submodule or the submodule itself. But note that after some changes are made, you'll need to pull the changes in the repository where you'll need them before making other changes.
This is maybe one of the biggest disadvantages of using git submodules instead of code-sharing platforms, however the purpose of this post is to explain how to share code with minimum configuration while keeping your code in your private repositories without using third-party platforms. If this doesn't fit your situation you can use other tools and platforms such as Bit.de, Storybook alongside Chromatic, Styleguidist and others.
Section 5: Testing shared components in isolation (Optional)
If you also want to view and test the shared components in isolation, then you can do that by adding a little more configuration.
For this, we'll need to use a build tool that will create the environment where we'll test the shared components. There are a few options here, but this example will use Parcel as it's light and quick and easy to setup. You can also use any other build tool of your choice, whichever best fits your scenario.
First, open the component-library project and in the root directory, create the following package.json file:
{
"name": "component-library",
"source": "index.html",
"scripts": {
"start": "parcel",
"build": "parcel build"
},
"devDependencies": {
"parcel": "latest"
}
}
Then run the following to install parcel:
npm install --save-dev parcel
Next, since we're working with React projects we need to install react and react-dom:
npm install react react-dom
Create the entry index.html file and paste the following code:
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My Component Library</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="index.js"></script>
</body>
</html>
Create an index.js file and paste the following code:
import { createRoot } from "react-dom/client";
import { App } from "./App";
const container = document.getElementById("app");
const root = createRoot(container)
root.render(<App />);
And finally create the App.js file with the Button component that we want to test:
import Button from './button';
export function App() {
return <Button />;
}
To run the application run:
npm run start
and to build run:
npm run build
These commands will build the application and write the output in dist directory. You can then open the local server on http://localhost:1234 and you should see the Button component.
While this post does not cover the details of deploying projects, once you have successfully set up the code-sharing mechanism, you can proceed with deploying and publishing the component library on your preferred server. By doing so, you gain the ability to preview and test the shared components at any time.
Section 6: Alternatives
Some other alternatives that provide similars value are:
- Bit.dev - a platform that facilitates component-driven development and component sharing across projects. It provides a centralized hub for developers to discover, share, and collaborate on reusable components. With Bit.dev, you can publish and version components, manage their dependencies, and integrate them into different projects, regardless of the framework or tooling being used. It offers features like component documentation, testing, and a package manager-like experience for sharing and consuming components.
- Storybook - a popular open-source tool for developing UI components in isolation. It allows you to build and organize a library of components, view them in different states, and document their usage. Storybook supports various frameworks like React, Vue, Angular, and more.
-
Styleguidist- a documentation tool specifically designed for React component libraries. It helps you create living style guides and documentation by providing an interactive environment where you can showcase and test your components.
- Chromatic -a tool that focuses on visual testing and UI review for component-driven development. It integrates with popular component frameworks like React, Angular, and Vue, and helps you catch UI bugs, perform visual regression testing, and collaborate with team members on component changes.
Conclusion:
While Git submodules offer a straightforward approach to code sharing, it's important to note that this approach may not be suitable for every scenario. Like any other tools and platforms, it has its own set of advantages and disadvantages. Therefore, it is crucial to thoroughly research and evaluate your specific needs before deciding on the best option for your project.
Consider factors such as the complexity of your codebase, the scale of your projects, the level of collaboration required, and the desired level of control over dependencies. Additionally, take into account the learning curve, maintenance overhead, and compatibility with your existing development workflow.
Remember, choosing the right approach is essential for long-term productivity and success.
Github examples:
Using enterkeyhint Attribute to Build Better Mobile Forms
— Do & Learn
If you're looking to improve how you build your mobile forms, you've come to the right place! In our previous post, "Inputmode Attribute Explained: Key to Better Mobile Forms", we explored how the inputmode attribute can improve input fields for mobile devices. Today, we're continuing that story with another valuable attribute: the enterkeyhint. This small yet powerful attribute can greatly enhance the user experience and accessibility of your forms on mobile devices. Let’s explore how to use this attribute and learn how to create more intuitive and user-friendly forms.What is enterkeyhint?The enterkeyhint is a global HTML attribute that allows developers to tell the users what action will occur when they press the enter key on a virtual keyboard, such as submitting a form, moving to the next input field or inserting a new line. While inputmode controls what kind of virtual keyboard will be shown, enterkeyhint indicates how the enter key will be labeled (or which icon will be shown).Providing a clear and relevant label or icon can make your form interactions smoother and more intuitive, especially on mobile devices where keyboard space is limited.How Does enterkeyhint Work?The enterkeyhint works on any form fields such as input, textarea or any other element that is editable (has contenteditable=true). It is an enumerated attribute and only accepts the following values:enterkeyhint="enter"Indicates that pressing the enter key on a virtual keyboard will insert a new line. The label shown depends on user agent and user language but it is typically something like: ↵ or 'Return'.For example, if you have a multi-line text input (like a textarea) and you set enterkeyhint="enter", the virtual keyboard will display the enter key with a label indicating that it performs a line break or simply inserts a new line, rather than performing a specific action such as form submission or search. enterkeyhint="done"Indicates that pressing the enter key on a virtual keyboard will complete the current action, usually submitting a form.This hint is typically used in forms where the user is expected to finish entering data and submit it. For example, if you have a text input field in a form, setting enterkeyhint="done" will display a "Done" label on the enter key of the virtual keyboard, signaling that pressing it will submit the form or complete the current input.enterkeyhint="go"Indicates to the user that pressing the enter key on a virtual keyboard will trigger a "go" action. This is typically used in contexts where the user is expected to submit a search query or initiate a navigation action.For example, if you have a search input field, setting enterkeyhint="go" would display a "Go" label on the enter key of the virtual keyboard, signaling to the user that pressing it will start the search process.enterkeyhint="next"Indicates that pressing the enter key on a virtual keyboard will move the focus to the next input field or element in the form rather than submitting the form or performing another action. It would display a "Next" label on the enter key.This makes the navigation between fields more intuitive for users.enterkeyhint="previous" Indicates that pressing the enter key on a virtual keyboard will move the focus to the previous input field or element in the form. It would display a "Previous" label on the enter key. This is probably not that commonly used like the "next" hint, however is can be useful in multi-field forms where users may need to navigate backward through fields they have already filled out. enterkeyhint="search" Indicates that pressing the enter key on a virtual keyboard will trigger a search action. This is useful for input fields where users are expected to enter search queries. By setting enterkeyhint="search", the virtual keyboard will display a label such as "Search" on the enter key.enterkeyhint="send" Indicates that pressing the enter key on a virtual keyboard will trigger a send action. It would display a "Send" label on the enter key. This is useful in contexts where the user is expected to send a message or submit a communication.If no enterkeyhint attribute is provided, the label on the enter key on the virtual keyboard defaults to the browser's or device's standard settings which may be generic, such as "Enter" or "Return" or if inputmode, type, or pattern attributes are used, the user agent might use contextual information from these attributes and display a suitable label or icon.Note: Applying the enterkeyhint attribute only informs the user what will happen on press on the Enter key. To fully improve the user experience and the accessibility of your forms you must also implement the sutable functionality such as automatically navigating though the form fields on keypress or submitting the form on press on Enter.ExamplesLet's see it in action. Bellow is a multi-step form with three simple fields and a button that is responsible for submitting the form. <form> <input type="text" enterkeyhint="next" placeholder="First name" /> <input type="text" enterkeyhint="next" placeholder="Last name" /> <input type="text" enterkeyhint="done" placeholder="Address" /> <button type="submit">Save</button> </form> As users fill out each field and press enter, they are guided through the form fields in order due to the enterkeyhint="next" attribute. When they reach the last field, the enterkeyhint="done" attribute signals that pressing on Enter key at this point will submit the form. Try out the example on your mobile device or using a virtual keyboard. Click on any field and notice the label in the right bottom corner. Save It should look something like this. (This example is on iOS, the keyboard shown will vary depending on what type of device is used). You can also apply this attribute dynamically using the enterKeyHint property of on a HTMLElement const firstName = document.getElementById("firstName"); const lastField = document.getElementById("lastName"); firstName.enterKeyHint = "Next"; lastField.enterKeyHint = "Done";When to Use enterkeyhintThe enterkeyhint attribute is useful when you want to control the label or icon displayed on the "enter" key on virtual keyboards. You should use it in cases where the default behaviour doesn't fully match the user experience you're trying to provide. Here are situations where you can use its benefits: Forms with Multiple Steps - As shown in the example above, when there are multiple fields or steps in a form and the functionality for field navigation is implemented, using enterkeyhint="next" or enterkeyhint="previous" can improve the user experience by informing them what will happen when they press Enter key. Search Fields - Probably the most common scenario is to apply enterkeyhint="search" on a search input field that performs a search on press on Enter key. Sending a Message- Similar to search fields, the attribute can be applied to an input or textarea fields that contain a message that will be sent on press on Enter key. Custom Actions - Sometimes, even though the browser can infer an appropriate label, you might want to override it for a better user experience. For example, on a numeric input field, the default key might be "Next," but you want the key to indicate "Go" or "Done."Browser supportenterkeyhint attribute is supported by most major browsers as shown on the table below. :root { --post-background-color: #2e5ba6; --post-content-color: #ffffff;} form.enterkeyhint-form-example { display: flex; flex-direction: column; gap: 1em; }
Privacy First: How to Securely Handle User Data in Forms
— Do & Learn
When working with forms that handle sensitive information like personal details, passwords, or financial data, paying attention to privacy is crucial. It’s about respecting your users and protecting their personal information. Every time you collect or process data through a form, you need to be clear about how you will use, store, or share this information. Here are some simple steps to help you build trust with your users.Limit Data Collection Only ask for the information you need to make your form work. For example, if you’re creating a signup form for a newsletter, you only need the user’s email address. Avoid requesting extra details such as phone numbers or addresses unless they are necessary. Similarly, for a contact form, asking for just a name and email address may be enough in most situations.Collecting only necessary data does not only reduces the risk of exposing personal information but also improves the user experience. Short, straightforward forms are easier to complete and less frustrating for users.Tip: Regularly check your forms to ensure they only collect necessary information. This keeps your forms user-friendly and helps protect personal data.Provide Clear Data Collection DetailsClearly inform users about what data you’re collecting and why. Make sure to always ask for their explicit permission before processing their sensitive information. Use clear labels: For example, instead of just a checkbox that says “I agree,” use labels like “I agree to receive emails at this address” Provide additional text: Include a brief description near the checkbox or consent request. For example, “We will use your email address only to send you updates and offers. You can unsubscribe at any time.” Highlight important details: If you are collecting sensitive information, make sure to explain why it’s needed and how it will be protected. For example, “We need your phone number to provide customer support. Your number will not be shared with third parties.”Tip: Make sure the consent request is easy to understand and does not use complicated legal terms. This helps users make informed decisions about their data.Bad approach: I agree Sign UpGood approach: I agree to receive newsletters at this email address. (We will use your email only to send updates and offers. You can unsubscribe at any time.) Sign UpHide/Mask Sensitive InformationFor fields that require sensitive information such as passwords, credit card numbers and CCV, use masking techniques to hide the user's input. This ensures that user's sensitive data is not exposed while they are typing. For example, show asterisks (****) instead of the actual characters in password fields, CVV or any other similar information.Bad approach: Password: CVV: SubmitGood approach: Password: CVV: SubmitAllow Data Access and UpdateGive users the option to view their data, make updates, or delete it if they want to. For example, if a user wants to change their email address, they should be able to update it easily in their account settings. This will help users feel in control of their personal information and build trust.Update Privacy Practices RegularlyStay up-to-date with changes in privacy laws, such as GDPR (General Data Protection Regulation) and CCPA (California Consumer Privacy Act). Regularly review and update your privacy practices to ensure compliance with these laws.Tip: Consider having a privacy expert review your policies periodically to ensure they meet legal requirements and best practices.ConclusionHandling user data with care is a legal requirement but also essential for building trust with your users. By following these steps, you can protect user privacy and make sure your forms are secure and trustworthy. Showing that you are committed to protecting personal information helps create a safe environment for your users, therefore increases your user acitvity and engagement. :root { --post-background-color: #005ae8; --post-content-color: #ffffff;}
Inputmode Explained: The Key to User-friendly Mobile Forms
— Do & Learn
If you’ve ever struggled with typing the right information into a web form on your phone, you’ll appreciate how much a simple change like inputmode can improve the experience. But what exactly is inputmode, and how can you use it to make your forms more user-friendly?What is Inputmode?inputmode is an HTML attribute that tells the browser which type of virtual keyboard to display when a user focuses on an input field. By showing the appropriate keyboard, it makes typing faster and reduces errors. It’s especially useful on mobile devices where keyboard layouts can change based on the type of data you need to enter. inputmode is primarily used on <input /> elements but it can also be applied on any other HTML element in contenteditable mode. How Does inputmode Work?When you add the inputmode attribute to an input field, you specify the type of data you expect users to enter. The browser then displays the most relevant keyboard. Here are all the values that inputmode can have: text: Default keyboard for text input. numeric: Number pad for numerical input. decimal: Number pad with a decimal point. tel: Telephone keypad for entering phone numbers. It includes the digits 0–9, the asterisk (*), and the pound (#) key email: Keyboard optimised for email addresses. Includes @ and .com buttons. url: Keyboard optimised for URLs (includes / and . buttons). search: Keyboard optimised for search input. For example, the return/submit key may be labeled "Search", along with possible other optimisations. none: No virtual keyboard. For when the page implements its own keyboard input control.ExamplesLet’s look at some examples of how to use inputmode in your forms:Numeric <label for="amount">Amount:</label> <input type="text" id="amount" inputmode="numeric" placeholder="Enter amount"/>The keypad on mobile will look something like this. (This can vary depending on the mobile OS, this example shows how it looks on iOS)Tel <label for="phone">Phone:</label> <input type="text" id="phone" inputmode="tel" placeholder="Enter your phone number"/>The keypad on mobile will look something like this:Email <label for="email">Email:</label> <input type="text" id="email" inputmode="email" placeholder="Enter your email"/>The keypad on mobile will look something like this:UrlHere is an example of using a <div> element in editable mode as a field: <label for="url">Url:</label> <div contenteditable="true" id="url" inputmode="url" placeholder="Enter a url"/>The keypad on mobile will look something like this:When to Use inputmodeIf you're using the HTML <input> element with a specific type attribute (other then 'text'), the keypad will be automatically shown depending on the type. However, if you need a more custom input or other editable element then you might need to use the proper inputmode. Using the correct inputmode will allow you to optimise the input experience for users, especially on mobile devices. Here are some situations where it can be helpful: Numeric: Credit Card Numbers Security Codes (e.g., CVV for credit cards) Bank Account Numbers Social Security Numbers Employee or Student ID Numbers Membership Numbers Serial Numbers for Products Decimal: Prices Weights Product Dimensions Coordinates (e.g., latitude and longitude) Financial Data (e.g., interest rates) Measurement Units (e.g., height, length) Tel: Phone Numbers Fax Numbers Email: Email Addresses Contact Forms URL: Website URLs API Endpoints Search: Search Fields on Websites Search Boxes in Applications Text: Names Addresses General Text Inputs By making these small adjustments, you can significantly improve the user experience on your web forms, making them quicker and easier to fill out.Browser supportinputmode attribute is supported by most major browsers as shown on the table below. :root { --post-background-color: #bee4da; }