Customization
The Qbit Design includes default skins for all components, which you can use directly. If you require customized designs for your components, you can create custom skins or do modifications to an existing skin. Follow Below steps to integrate a custom skin into a component.
Skins and Customization
In Qbit Design customizing UI designs can be simply done using a custom skin. Qbit Design renderer is intelligent enough to identify which skin to be loaded during the runtime.
Customize skin
Let's create a skin from the scratch. To create a skin just you need to know the props which are available. Check the official documentation to know about the required element prop.
Skin folder structure
You can store your skin as your needs. Here is a way to store the skins in a proper way. Please refer below structure.
Project file
├── src
│ └── skins
│ ├── default skins
│ │ └──element skins folder
│ │ └──element skins
│ └── optional skin
│ └──element skins folder
│ └──other skins for the element
│ └──other skins for the element
The standard location to save your custom skin is under src/skins/<custom_skin_name>
.
UI Design
For the styling you can use the tailwind
or bootstrap
or display it with an svg
Install tailwind via npm
npm install -D tailwindcss postcss autoprefixer
Install tailwind via pnpm
pnpm add -D tailwindcss postcss autoprefixer
Install bootstrap via npm
npm install bootstrap
Install bootstrap via pnpm
pnpm add bootstrap
Display with an SVG
An SVG (Scalable Vector Graphics) is a widely used format for displaying vector images, icons, and UI components in web applications. Using SVG for UI design ensures scalability, flexibility, and high-quality rendering across different screen sizes.
Let's Start to Create the Skin
To create a skin, define a React functional component that takes the appropriate props. Refer to the documentation for the property definitions (type definition interface name) to pass the correct props.
Example: Tab Item Element Skin
Example Output
Tab Item Skin Code
const TabItemSkin: com.qbit.Skin<TabItemProps> = (props) => {
const { name, onClick, disabled, active, className } = props;
return (
<button
className={`${className} ${active ? 'border-b-2 border-blue-500 text-blue-500' : 'text-gray-500 hover:text-blue-500'}
${disabled ? 'cursor-not-allowed opacity-50' : ''}`}
onClick={(e) => {
if (!disabled) {
onClick?.(e);
}
}}
>
{name}
</button>
);
};
export default TabItemSkin;
Step-by-Step Code Breakdown
Define the Functional Component
const TabItemSkin: com.qbit.Skin<TabItemProps> = (props) => {
TabItemSkin
is a functional component.- It accepts props defined by
TabItemProps
.
Destructure Props
const { name, onClick, disabled, active, className } = props;
name
: Text inside the tab button.onClick
: Function to handle tab click.disabled
: Boolean that disables interaction.active
: Boolean indicating if the tab is selected.className
: Custom styles from the parent component.
Rendering the Button
The skin renders a <button>
element, styled dynamically using Tailwind CSS classes.
Dynamic Styling
-
The
className
combines custom classes and conditional classes based on theactive
anddisabled
props. -
Styling Behavior:
- If
active
istrue
:- Adds styles:
border-b-2 border-blue-500 text-blue-500
(active tab appearance with a blue underline and blue text).
- Adds styles:
- If
active
isfalse
:- Adds styles:
text-gray-500 hover:text-blue-500
(gray text by default, turning blue on hover).
- Adds styles:
- If
disabled
istrue
:- Adds styles:
cursor-not-allowed opacity-50
(disables pointer events and makes the button semi-transparent).
- Adds styles:
- If
Click Handler
- The button’s click event is handled via the
onClick
function passed as a prop. - If
disabled
istrue
, theonClick
function is not executed. - Optional chaining (
onClick?.(e)
) ensures the function is only called if it exists.
Button Content
- The
{name}
prop displays the name inside the button.
Skin Usage
To apply the TabItemSkin, we need to pass it into the renderers
prop of the parent Tab
component. The renderers
prop accepts two properties:
renderer
→ Defines the parent element's skin.childRenderer
→ Defines the child elements' skin (required).
Example: Using the Tab Skin in a Page
<Tab
keyExtractor={(value: string, i: number) => `${value}-${i}`}
renderers={{ renderer: TabSkin, childRenderer: TabItemSkin }}
>
<TabItem active={true} name="Tasks" content={<SampleContent />} />
<TabItem active={false} name="Removed task" content={<Element />} />
<TabItem active={false} name="Sign in/up" content={<Login />} />
</Tab>
Breaking Down the renderers
Prop
renderer
(Parent Skin)
renderer: TabSkin
- Purpose: Defines how the Tab container looks and behaves.
- Example: If
TabSkin
styles the tab container, it could define background colors, padding, borders, etc. - Effect: This affects the whole tab group, not individual items.
childRenderer
(Child Skin)
childRenderer: TabItemSkin
- Purpose: Controls the appearance of individual tab items.
- Example:
TabItemSkin
styles each tab button, including text color, borders, and hover effects. - Effect: It applies to all
TabItem
elements inside theTab
component. - Requirement:
childRenderer
is mandatory, ensuring every tab item has a consistent style.
How It Works
- The
Tab
component takes a list of tab items. TabSkin
defines the overall layout and appearance of the tab container.TabItemSkin
ensures each tab item is styled correctly.- The
active
prop changes the visual state of a selected tab.
This approach allows customization while maintaining modularity in your design.
Styling
In TypeScript, you need to specify the type for the skin. This can be done as follows:
com.qbit.Skin<{ComponentProps}>
Here, ComponentProps
varies for each component based on its specific properties.
Simple Button Design
Below is an example of a simple button design using a custom skin.
Here's how you can structure the documentation with the requested example and sandbox embed:
Example 01: Simple Button Design
const CustomizedButton: com.qbit.Skin<ButtonProps> = (props: com.qbit.SkinProps<ButtonProps>) => {
const { value, onClick, disabled } = props;
return (
<button
disabled={disabled}
onClick={onClick}
className="flex w-full justify-center rounded-md bg-[#212121] px-3 py-2 text-sm/6 font-semibold text-white shadow-sm hover:bg-neutral-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#212121]"
>
{value}
</button>
);
};
export default CustomizedButton;
Example 02: Hover Animation Button Design
const CustomizedButton: com.qbit.Skin<ButtonProps> = (props: com.qbit.SkinProps<ButtonProps>) => {
const { value, onClick, disabled } = props;
return (
<button
type="button"
disabled={disabled}
onClick={onClick}
className="relative inline-flex items-center justify-start px-6 py-3 overflow-hidden font-medium transition-all bg-white rounded border-2 border-[#FBDD07] group"
>
<span class="w-48 h-48 rounded rotate-[-40deg] bg-[#FBDD07] absolute bottom-0 left-0 -translate-x-full ease-out duration-500 transition-all translate-y-full mb-9 ml-9 group-hover:ml-0 group-hover:mb-32 group-hover:translate-x-0"></span>
<span class="relative w-full text-left text-[#212121] transition-colors duration-300 ease-in-out">Button Text</span>
{value}
</button>
);
};
export default CustomizedButton;