To ensure an efficient and effective development process, it is crucial for developers to select a UI library or framework that provides a balance of pre-made components and customization choices.
Although many UI libraries and frameworks provide pre-made styles and components, some may not provide enough flexibility for customization due to their rigid styles and patterns. To be able to easily modify the default styles, design decisions, and patterns, customization is necessary. This means being able to adjust the styles and components to fit the unique needs of a project.
In this tutorial, we’ll introduce you to Camome UI, a frontend framework for React and CSS. We will use this flexible framework to demonstrate how to design highly customizable user interfaces.
Jump ahead:
Camome UI is an easy-to-use UI framework for React and CSS that allows users to create website user interfaces. Camome UI is built on top of CSS Modules; this allows users to create various styles of components by leveraging the full power of CSS without using run-time JavaScript. This approach helps improve the performance of the user interface and provides greater flexibility in design options.
Camome UI comes with highly reusable components that are intended to blend in with standard design websites, but they can also be highly customized to suit any style for your site.
The following principles were kept in mind when developing Camome UI:
When developing components, accessibility is critical. Camome UI states that it may not be perfect at accessibility, but that they are giving serious attention to it.
The aria-labelledby
and aria-describedby
values are followed by Camome UI input components when using the <Formfield />
component.
The Switch
component is built using CSS alone but it is provided keyboard navigation and focus management. By using the <details />
element, Accordion automatically supports opening and closing without client-side JavaScript.
Implementing dark mode with Camome UI is flexible and straightforward because it comes by default.
To enable light and dark themes in your app, you must specify the data-theme
attribute:
<!DOCTYPE html> <html data-theme="<light or dark>"> <!-- Content --> </html>
The light and dark themes are then styled as follows in theme.css
:
@layer cmm.theme { :root[data-theme="light"] { --cmm-color-primary-font: var(--cmm-color-primary-7); --cmm-color-primary-emphasis: var(--cmm-color-primary-6); {...} } /* And dark theme as well... */ }
It can also be customized as follows in your own CSS file:
:root[data-theme="dark"] .your-class { /* Your styles for dark theme... */ }
It can also be customized independently.
Keeping JavaScript usage to a minimum on your pages is crucial for a fast user experience. A Camome UI component like Button
costs 1.42KB when imported from @camome/core/Button
(including CSS), and an additional 4KB from the global CSS.
Camome UI is framework agnostic. It offers guides for integrating with some frontend frameworks including Astro, Next.js, and, Vite.
Camome UI can also be used as a CSS framework similar to Bootstrap, despite being primarily designed as a React library, by importing bundled CSS. Other frameworks, such as Vue or Svelte, can be easily supported by simply binding class names. It also allows Integration with headless UI libraries such as Headless UI, React Aria, Radix Primitives, and Reach UI for building complex UIs such as Menu, Dialog, and Tab:
<head> <link href="https://unpkg.com/@camome/system@latest/dist/theme.css" rel="stylesheet" /> <link href="https://unpkg.com/@camome/core@latest/dist/components.css" rel="stylesheet" /> </head> <body> <button class="Button Button--primary Button--soft">Click me</button> </body>
Camome UI is also entirely composed of React components, CSS Modules, and theme.css
, making it simple to inject into your codebase.
No JavaScript runtime means that JavaScript codes are not executed in both the browser’s runtime environment and the Node runtime environment. This is done because no event handlers or useEffect
are used and instead, CSS Modules are used for styling and can also be used as a pure CSS framework.
Camome UI offers CSS Cascade Layers to ensure that your customized CSS styles always prevail due to one disadvantage of CSS Modules: the difficulty of overriding styles.
With Camome UI, you don’t need to always include !important
to your styles or worry about the order or specificity when overriding styles because all styles outside the @layer
block override the styles enclosed within the @layer
block.
Before we dive into using Camome UI to design user interfaces, let’s look at the Camome design system. The Camome UI design system is divided into sections covering Color palette, Typography, and Misc.
The color palette for the Camome UI design system is a collection of colors used to create user interfaces that are aesthetically pleasing and enjoyable to use while promoting consistency. The color palette is broken down into three categories: Shade, Semantic, and Template. Shade is the most primitive.
Semantic can be used generally anywhere; for example, font.base
is used to add white or gray to your fonts using font.onEmphasis
:
h1 { color: var(--cmm-color-font-base); }
Templates are used for specific UI patterns. For example, a button has several templates that may be changed using the variant property’s solid
, soft
, or outline
options:
button:hover { background: var(--cmm-primary-solid-bgHover); }
Typography includes the styles for setting font family, font size, and font weight:
<style> h1{ font-family: var(--cmm-font-family-base) // font family font-size: var(--cmm-font-size-sm) // font size font-weight: var(--cmm-font-weight-bold) // font weight } </style> <body> <h1>Hello World!</h1> </body>
Misc includes the styles for setting shadows and radius:
<style> button{ border-radiue: var(--cmm-radius-2xl); box-shadow: var(--cmm-shadow-xl); } </style> <body> <button>Click Here</button> </body>
Camome UI components are pre-built elements that look the same no matter where they are placed on the webpage. They adhere to patterns that are only effective when the proper class names and modifiers are used.
To add a Camome UI button component, you just need to specify the Button
class to the button
element:
<button class="Button">Button</button>
This will create a default Camome UI button. We can extend the button with additional classes to specify its color scheme, type, state, and variations.
The class names Button--solid
, Button--outline
, Button--ghost
, and Button--soft
can be used to identify the button variations. Class names are Button--primary
, Button--neutral
, Button--success
, and Button--danger
.
You specify the different states of your button, such as loading or disabled, by specifying role="status"
and disabled="true"
respectively:
// Loading state <button class="Button Button--solid Button--primary Button--md"> <span class="Button__startDecorator"> <div role="status" class="Spinner Spinner--sm"> <svg>...</svg> <span class="visually-hidden">Loading...</span> </div> </span> Saving... </button> // disabled <button class="Button" disabled="true"> Solid </button>
We can also provide Button--sm
, Button--md
or Button--large
to change the button’s size:
<button class="Button Button--sm">Small</button>
The <kbd>
tag denotes text representing a keyboard button or shortcut. This tag can also be used for voice input or any other text input device.
The text content is displayed by default in a monospace font. To create the UI of a keyboard button, your code should look similar to this:
<div> <kbd class="Kbd">⌘</kbd> <span>+</span> <kbd class="Kbd">K</kbd> </div>
For example, you can add styles to increase the font size; simply set the font-size
property to change size:
<div style="font-size: var(--cmm-font-size-lg);"> <kbd class="Kbd">Ctrl</kbd> + <kbd class="Kbd">Alt</kbd> + <kbd class="Kbd">Delete</kbd> </div>
The Camome UI Message
component is used to highlight important information. The Message
component can be added by specifying the Message
class name. This will automatically produce a message
. By adding the Message-info
, Message-warn
, Message-error
, or Message-success
classes, we can give the message different variations:
<div class="Message Message-info"> <span class="Message__icon"> <svg>...</svg> </span> <div class="Message__title" id=":R0:">This is a title</div> <div class="Message__content"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. </div> </div>
Alert
is similar to Message
; all you need is to specify the role="alert"
attribute:
<div role='alert' class="Message Message--info"> <span class="Message__icon"> <svg>...</svg> </span> <div class="Message__content">This is an alert message</div> </div>
Tooltips show the user additional information about a page element or feature. Use the class name Tooltip__target
and the role="tooltip"
attribute to target the element, and the data-placement
attribute to specify the position of the tooltip:
<div class="Tooltip__target"> <button class="Button Button--solid Button--primary Button--sm">Top</button> <div role="tooltip" class="Tooltip__content" data-placement="top"> This is a tooltip </div> </div>
Camome UI can be added to your project in different ways with different frameworks. It can be added to your project using npm
, yarn
, or pnpm
. After that, you will also need to configure plugins or loaders for webpack or Rollup if you are using Next.js, Astro, or Vite because Camome UI is written in JavaScript and CSS Modules in Sass as they cannot be directly imported from JavaScript.
Look at the integration guide to learn how to set it up with your preferred frontend framework.
According to their docs, Camome UI is not yet stable — Breaking changes may be introduced without increment of significant version number. When you update
@camome/*
, see changelogs to make sure your code is not affected by breaking changes.
For this tutorial, we will be using the CDN version. Create an index.html
file within a new folder camome-project
and add the CDN link to the head
tag element. Your code should look like the one below:
<!DOCTYPE html> <html lang="en" data-theme='light'> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> // camome UI CDN link <link href="https://unpkg.com/@camome/system@latest/dist/theme.css" rel="stylesheet" /> <link href="https://unpkg.com/@camome/core@latest/dist/components.css" rel="stylesheet" /> <title>Camome UI Landing page</title> </head> <body></body>
The data-theme
attribute is what Camome used to define light and dark modes.
Here, we will put all that we’ve learned so far into building a landing page. We’ll implement a couple of Camome UI components and design systems. We will create a basic homepage that includes Camome UI components and the pre-existing styles that Camome UI provides by default for both light and dark modes.
Subsequently, we will modify the user interface to integrate our individualized styles and design preferences. Here’s what our finished project will look like:
Using Camome to design highly customizable UI
Using Camome to design highly customizable UI by miracle
Open the camome-project/index.html
file we previously prepared to begin creating our home page. Following that, we’ll make a nav
element to house our navigation link and toggle button:
<nav> <div class="Tab__group"> <div class="Tab__list" role="tablist" aria-orientation="horizontal"> <div class='tab'> <a href='#' class="Tab Tab--active">Home</a> <a href='#' class="Tab">FAQ</a> <a href='#' class="Tab">Contact Us</a> </div> <button class="Button Button--solid Button--primary Button--md'>dark</button> </div> </div> </nav>
This code creates a navigation bar for a website. The navigation bar has a group of tabs with links to different pages on the website such as the homepage, FAQ page, and contact page. The active tab, or the one currently selected, is highlighted with a different color.
In addition to the tabs, there is also a button that can be clicked to toggle between light and dark. We will be handling the functionality of the toggle button with JavaScript.
Now let’s add our Hero
section:
<header> <div class='container'> <h1>Light weight, accessibleUI framework for React and CSS</h1> <p>Camome UI enables you to build various styles of components without run-time JavaScript by fully utilizing the power of CSS.</p> <div class="Tooltip__target"> <button class="Button Button--solid Button--primary Button--lg"> Hover me </button> <div role="tooltip" class="Tooltip__content" data-placement="bottom"> Camome UI is a React component library and a CSS framework. </div> </div> </div> <form> <div class="FormField FormField--fill"> <label class="FormFieldLabel"> First name </label> <input class="TextInput TextInput--md TextInput--fill" type="text" placeholder="John" name="firstName" /> </div> <div class="FormField FormField--fill"> <label class="FormFieldLabel"> Email </label> <input class="TextInput TextInput--md TextInput--fill" type="email" placeholder="example.com" name="email" /> </div> <div class="FormField FormField--fill"> <label class="FormFieldLabel"> Job title </label> <select class="Select Select--md Select--fill" name="jobTitle"> <option value="developer">Developer</option> <option value="designer">Designer</option> <option value="other">Other</option> </select> </div> <button class="Button Button--solid Button--primary Button--md" type="submit"> Submit </button> </form> </header>
The markup code is used to create a header section for a website. The header includes a title and description and a button that, when hovered over, displays a tooltip. Additionally, there is a form included that allows users to input their name, email, and job title with a submit button.
With this, let’s add styles to our site to make it look good. We will style our app using the Camome design system. This will give us more power to easily customize our styles. Create a new camome-project/styles.css
file, link the CSS file to the HTML file, and add the code below:
body { max-width: 1080px; width: 100%; height: 100vh; margin: 0 auto; padding: 2rem 1rem; } nav { display: flex; margin-bottom: 5rem; } nav .tab { display: flex; } nav .Tab__list { display: flex; align-items: center; justify-content: space-between; } header { display: flex; align-items: center; justify-content: space-between; gap: 5rem; } .container{ flex: 0 0 40%; max-width: 40%; } header h1 { font-size: var(--cmm-font-size-2xl); } header p { margin: 2rem 0 } form { flex: 0 0 60%; max-width: 60%; display: grid; gap: 1.5rem; color: var(--cmm-color-neutral-0); background: var(--cmm-color-neutral-7); padding: 1rem; border-radius: var(--cmm-radius-lg); } select, input{ color: var(--cmm-color-neutral-7); }
Styling using Camome UI is usually variable and starts with the prefix -cmm-
. For example, var(--cmm-font-size-2xl)
will increase the font size by 24px.
To add and customize the dark mode user interface, we will adjust the background-image
of the webpage’s body and background-color
of the hover button
. Additionally, we will modify the background-color
of the form
, input
, and select
elements. These instances can serve as helpful references for making additional modifications to the pre-existing styles within Camome UI.
Inside the styles.css
file, add the code below:
[data-theme="dark"] body{ background: url("https://media.giphy.com/media/aRZ4vTsHnyW6A/giphy.gif"); } [data-theme="dark"] .container button { background: linear-gradient( to right, hsl(240deg 60% 40%) 0%, hsl(300deg 80% 40%) 100% ); } [data-theme="dark"] form{ background: linear-gradient( to right, hsl(240deg 60% 40%) 0%, hsl(300deg 80% 40%) 100% ); } [data-theme="dark"] select, input{ color: var(--cmm-color-neutral-7); background: var(--cmm-color-neutral-0); }
The UI for the light mode will not change once we have successfully added these custom styles to our CSS file. But, we’ve customized our dark mode, which will make it look different.
Now, handling click
events in JavaScript will be the last step. First, add an id
attribute with a toggle
value to the navigation button. That way, when we click on it, we will be able to switch between dark and light modes:
<button class="Button Button--solid Button--primary Button--md' id='toggle'>dark</button>
To handle the switch between the light and dark mode user interface, add the following code to the index.js
file:
const toggle = document.getElementById("toggle"); const html = document.documentElement; toggle.addEventListener("click", () => { if (html.getAttribute("data-theme") === "light") { html.setAttribute("data-theme", "dark"); document.getElementById('toggle').innerHTML = 'light' } else { html.setAttribute("data-theme", "light"); document.getElementById('toggle').innerHTML = 'dark' } });
Camome UI is a React component framework that provides the same styling benefits as Tailwind CSS but handles all of the details for you. This library contains meticulously constructed components, allowing you to concentrate on accessibility, component composition, keyboard navigation, style overrides, and other important tasks.
When using various applications, it is often difficult to modify styles to meet specific design needs for a particular situation. In the case of Tailwind CSS, users may need to determine the most effective method to override certain classNames
or create their own CSS. Conversely, with Camome UI, overrides are simple because their styles are based on CSS modules, and can be easily adjusted.
Tailwind CSS supports dark mode for all of its components through the use of a dark variant. On the other hand, Camome UI components can be used in both light and dark modes, and you can also create custom light and dark mode experiences for your entire application.
Tailwind CSS requires the user to manage semantic HTML structure, adhere to WAI-ARIA requirements, enable keyboard navigation, and so on. On the other hand, Camome UI offers the ease of use of Tailwind as well as all of these other advantages pre-packaged.
Being a utility-first approach, Tailwind CSS usually uses many classes in HTML. The size of your HTML file may consequently grow larger during download. As a larger HTML file could take longer to download and render in the browser, it can also affect how quickly the page loads. On the other hand, the Camome UI component costs 1.42KB (including CSS), and an extra 4KB of global CSS is required.
In this guide, we looked at the Camome UI framework and its features, as well as explored the components and design system. We displayed some examples and guided you through the process of incorporating Camome UI into your webpage development. We also demonstrated how to substitute predefined styles with our unique styles. Although we concentrated on overriding dark mode styles, you can apply the information acquired from this guide to override light mode styles as well as overriding components.
In general, styling with Camome starts with the prefix -cmm-
and customizing for either light or dark mode starts with [data-theme="<dark or light>"]
. There are many styles that can be modified for both modes, allowing for a multitude of customization options for your web pages.
Good luck using Camome UI in your next project!
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.