hintu
v1.3.2
Published
Hintu by NguyenTheHuy
Downloads
59
Maintainers
Readme
hintu
React library used to design admin page UI faster and simpler.
Installation
Using npm:
npm install hintuUsing style:
import "hintu/dist/styles.css"Features
- UI Table Design
- Form Data & FieldArray Data
- Buttons with Multiple Themes
- Admin Website Layout
- Loading Page
- Data Formatting Functions
- Notification & Swal
- Process Bar
- Tab Bar
- Stepper
- Tooltip
- Chart
- Animation Component
Chart

import { LineChart,CurveLineChart,ColumnChart,PieChart,CircleChart } from 'hintu';
import "hintu/dist/styles.css"
const en = Array.from({ length: 11 }, (_, i) => (Math.floor(Math.random() * (2900 - 900 + 1)) + 900));
const en1 = Array.from({ length: 12 }, (_, i) => (Math.floor(Math.random() * (2900 - 900 + 1)) + 900));
const en2 = Array.from({ length: 12 }, (_, i) => (Math.floor(Math.random() * (2900 - (-500) + 1)) - 1000));
const label = Array.from({ length: 12 }, (_, i) => (`T${i + 1}`));
const Test = () => {
return (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1.3fr", gap: "10px" }}>
<div style={{ backgroundColor: "white", width: "100%", height: "300px" }}>
<LineChart
data={
[
{ label: "Tiktok", values: en },
{ label: "Facebook", values: en1 },
{ label: "Intagram", values: en2 },
]
}
labelColumns={label}
colors={[" #4caf50", " #f44336", "rgb(255, 1, 221)", "rgb(3, 163, 153)", "rgb(255, 225, 1)"]}
chartName="Basic Metrics"
/>
</div >
<div style={{ backgroundColor: "white", width: "100%", height: "300px" }}>
<CurveLineChart
data={
[
{ label: "Online", values: en },
{ label: "Office", values: en1 },
]
}
labelColumns={label}
colors={[" #4caf50", " #f44336", "rgb(255, 1, 221)", "rgb(3, 163, 153)", "rgb(255, 225, 1)"]}
chartName="Conversion Performance Metrics"
/>
</div >
<div style={{ backgroundColor: "white", width: "100%", height: "300px" }}>
<ColumnChart
data={[
{ label: "T1", values: [1050, 500, 5350] },
{ label: "T2", values: [4500, 3000, 6000] },
{ label: "T3", values: [800, 1400, 900] },
]}
labelColumns={["Bounce Rate", "Avg. Session Duration", "Landing Page Performance"]}
colors={[" #4caf50", " #f44336", "rgb(255, 1, 221)", "rgb(3, 163, 153)", "rgb(255, 225, 1)"]}
chartName="Optimization & A/B Testing Metrics"
/>
</div >
<div style={{ width: "100%", height: "300px", display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px" }}>
<div style={{ backgroundColor: "white", width: "100%", height: "300px" }}>
<PieChart
data={[
{ label: "Google Ads", value: 20 },
{ label: "Facebook Ads", value: 10 },
{ label: "TikTok Ads", value: 40 },
{ label: "E-Commerce", value: 30 },
{ label: "Other", value: 3 }
]}
colors={[" #4caf50", " #f44336", "rgb(255, 1, 221)", "rgb(3, 163, 153)", "rgb(255, 196, 1)"]}
chartName="Ad Budget Allocation by Channel"
labelPosition='right'
/>
</div >
<div style={{ backgroundColor: "white", width: "100%", height: "300px" }}>
<CircleChart
percent={50}
label='Revenue'
strokeWidth={20}
stylePercent={{ fontSize: "35px", color: "green" }}
chartName="Completion Rate"
/>
</div >
</div >
</div >
);
};
export default Test;- PROPS CircleChart
| Prop Name | Type | Default | Description |
| -------------- | --------------- | -------------- | ----------------------------------------------------------------------- |
| percent | number | (required) | The percentage to display (0 to 100). |
| size | number | undefined | Diameter of the chart. If not set, it fills the container responsively. |
| strokeWidth | number | 10 | Thickness of both background and progress circles. |
| color | string | "#4caf50" | Color of the progress arc. |
| label | string | "" | Optional text rendered below the circle chart. |
| styleLabel | CSSProperties | undefined | Custom inline style for the label. |
| stylePercent | CSSProperties | undefined | Style for the percentage number inside the chart (e.g., font, color). |
| style | CSSProperties | undefined | Wrapper div styling for full control over layout/margin/padding/etc. |
- Props ColumnChart
| Prop Name | Type | Default | Description |
| -------------- | --------------- | -------------- | ---------------------------------------------------------------- |
| data | DataPoint[] | required | Array of data groups, each with a label and array of values. |
| labelColumns | string[] | [] | Names of series corresponding to each value in values. |
| colors | string[] | [] | Colors assigned to each column by index. |
| height | number | undefined | Total chart height in pixels. |
| width | number | undefined | Total chart width in pixels. |
| widthColunm | number | undefined | Width of each individual column in pixels. |
| style | CSSProperties | undefined | Custom CSS styles applied to the chart container. |
| chartName | string | "Chart Name" | Title shown at the top of the chart. |
- Props LineChart
| Prop Name | Type | Description | Default Value |
| -------------- | --------------------------------------- | -------------------------------------------------------------------------------------------- | -------------- |
| data | { label: string; values: number[] }[] | Array of data points. Each item has a label and an array of values representing series data. | Required |
| labelColumns | string[] | Array of series names displayed in the legend. | [] |
| colors | string[] | Array of colors corresponding to each series, used for lines and points on the chart. | [] |
| style | CSSProperties | Custom CSS styles applied to the main container of the chart. | {} |
| chartName | string | Title displayed at the top of the chart. | "" |
- Props CurveLineChart
| Prop Name | Type | Description | Default Value |
| -------------- | --------------------------------------- | -------------------------------------------------------------------------------------------- | -------------- |
| data | { label: string; values: number[] }[] | Array of data points. Each item has a label and an array of values representing series data. | Required |
| labelColumns | string[] | Array of series names displayed in the legend. | [] |
| colors | string[] | Array of colors corresponding to each series, used for lines and points on the chart. | [] |
| style | CSSProperties | Custom CSS styles applied to the main container of the chart. | {} |
| chartName | string | Title displayed at the top of the chart. | "" |
- Props PieChart
| Prop Name | Type | Description | Default Value |
| --------------- | ---------------- | --------------------------------------------------------------------------------- | ------------- |
| data | PieChartData[] | Array of data slices, each with a label and a numeric value. | Required |
| colors | string[] | Array of colors for each slice of the pie. If not provided, defaults to gray/red. | [] |
| chartName | string | Optional title displayed below the chart. | "" (empty) |
| style | CSSProperties | Custom CSS styles applied to the chart container. | {} (empty) |
| labelPosition | string | "right" | "left" | "bottom" | "top" label render position | "top" |
Form data

import * as React from 'react';
import {
Button, FieldColumn, FieldData, FieldGrid, Form,
InputDate, InputDropdown, InputMultiDropdown,
InputNumber, InputPassword, InputText
} from "hintu";
const dataSelect = [
{ name: "A01", id: 1 },
{ name: "A02", id: 2 },
{ name: "A03", id: 3 }
];
const validator = (data) => data ? "" : "Must be";
const validatorGrid = (data) => data.length > 0 ? "" : "Must be";
export const elementP = () => <p></p>;
const Text = () => (
<div style={{ backgroundColor: "white" }}>
<Form
initialValues={{ product: [] }}
onSubmit={(dataItem) => console.log(dataItem)}
render={(dataContext) => (
<div>
<FieldData component={InputText} suffix="huy" label="Data" name="user" validator={validator} />
<FieldData component={InputNumber} prefix={<i className="fa-solid fa-house" />} label="Price" name="price" validator={validator} />
<FieldData component={InputDate} hint="Lon hon 1" label="ETD" name="etd" validator={validator} />
<FieldData component={InputPassword} prefix="hihi" label="Password" name="password" validator={validator} />
<FieldData component={InputDropdown} data={dataSelect} fieldRender="name" fieldItemKey="id" label="Dropdown" name="dropdown" validator={validator} />
<FieldData component={InputMultiDropdown} data={dataSelect} fieldRender="name" fieldItemKey="id" label="Multi Dropdown" name="multidropdown" validator={validatorGrid} />
<FieldGrid name="product" validator={validatorGrid}>
<FieldColumn component={InputDropdown} data={dataSelect} fieldRender="name" fieldItemKey="id" label="Dropdown" name="dropdown" validator={validator} width={300} onChange={(e) => console.log(e)} />
<FieldColumn
label="Quantity"
name="quantity"
component={({ record }) => record?.dropdown?.name === "A02" ? InputNumber : elementP}
validator={({ record }) => record?.dropdown?.name === "A02" ? validator : null}
/>
</FieldGrid>
<button type="submit">Ok</button>
<button type="button" onClick={() => dataContext.handleChangeInitial("multidropdown", [dataSelect[1]])}>Change</button>
<button type="reset" onClick={dataContext.onReset}>Reset</button>
</div>
)}
/>
</div>
);
export default Text;- Props FieldData and FieldColumn
| Prop Name | Type | Required | Description |
| ---------------- | ------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------- |
| label | string | Yes | Label displayed above the field. |
| name | string | Yes | Field name used for binding in the form context. |
| component | React.ComponentType<{...}> | Yes | A specific input component used to render the field (see list below). |
| hint | string \| null | __ | Optional helper text shown below the field. |
| required | boolean | Yes | Indicates whether the field is required. |
| suffix | ReactNode | __ | Content shown at the end (right side) of the field. |
| prefix | ReactNode | __ | Content shown at the beginning (left side) of the field. |
| onChange | (e: React.ChangeEvent<HTMLInputElement \| HTMLTextAreaElement>) => void | __ | Standard input change handler. |
| validator | (value: any, values?: any, index?:number) => string \| undefined | __ | Value is the value of the specified input, (value: optional) is the |
| | | | value of the entire form data. (Index: optional) is the row index |
| | | | of the FieldGrid in the FieldColumn. Returns an empty string if valid,|
| | | | otherwise returns an error message string |
| fieldRender | string | __ | Custom render identifier (used for conditional rendering). |
| fieldItemKey | string | __ | Key used to uniquely identify field items (useful in lists). |
| filterable | boolean | __ | Enables search/filter in dropdowns (default is true). |
| readonly | boolean | __ | Makes the field read-only. |
| disabled | boolean | __ | Disables the field from user interaction. |
| checked | boolean | __ | Checkbox or radio selection state. |
| accept | (".pdf" \| ".doc" \| ".xlsx" \| ".pptx" \| ".png" \| ".jpg")[] | __ | Accepted file types (used with InputFile). |
| valueCheckbox | any | __ | Value for checkbox or radio input. |
| rows | number | __ | Number of rows for textarea (InputTextArea only). |
| changeDropdown | (value: any) => void | __ | Callback when dropdown value changes. |
| data | any[] | __ | Options data for dropdown, checkbox group, or radio group. |
| itemRender | (item:T) => string | __ | Custom display for dropdown records |
| Component Name | Description |
| -------------------- | ------------------------------------------------ |
| InputText | Basic single-line text input. |
| InputPassword | Password input with hidden characters. |
| InputNumber | Numeric input field. |
| InputDate | Date picker input. |
| InputDropdown | Single-select dropdown list. |
| InputMultiDropdown | Multi-select dropdown list. |
| InputTextArea | Multi-line text input. |
| InputCheckBox | Single or grouped checkboxes. |
| InputRadio | Radio button group. |
| InputFile | File upload input (with file type restrictions). |
| InputImage | Image uploader with optional preview. |
| InputTime | Time input field. |
| InputDateTime | DateTime input field |
Table Grid

You can use table grid with java spring boot maven library I built. Refer to Link Maven Library
import React, { useCallback, useEffect, useState } from 'react';
import { Button, Column, TableGrid, TableToolbar } from 'hintu';
export default function Form() {
const [state, setState] = useState({ size: 15, page: 0, sort: null, filter: [] });
const [data, setData] = useState([]);
const fetchData = useCallback(async () => {
// TODO: Fetch data from API
//Then the data after fetching goes into state.
//Note that table uses java paging for pagination so it should be combined with java Pageable to render as well as sort and filter data in the direction of dividing pages from the server.
//serverSide if page split on server side then serverSide is true. and it is default. but if split on client side then it is false
}, []);
useEffect(() => { fetchData(); }, [state]);
return (
<TableGrid state={state} setState={setState} maxHeight="calc(100vh - 180px)" key={data} name="plan" data={data && data.content ? data.content : []} totalElements={data && data.totalElements ? data.totalElements : 0}>
<TableToolbar><Button>AddNew</Button></TableToolbar>
<Column header="ID" accessor="id" type="number" />
<Column header="Name" accessor="name" type="string" Cell={({ data, dataItem }) => <p>{data} ({dataItem.code})</p>} />
< Column header={"Status"} accessor={"status"} type={"select"} filterOptions={statusArray} filterValue='code' filterRender='name' />
</TableGrid>
);
}
- Props Column
| Prop Name | Type | Required | Description |
|-------------------|------------------------------------------------------------------------------------------------------|----------|------------------------------------------------------------------------------------------------------|
| header | string | Yes | The column header label. |
| accessor | string | Yes | Key used to access the value from the dataItem object. |
| type | "string" | "number" | "date" | "boolean" | "select" | __ | Data type of the column, used for sorting and filtering logic. |
| defaultVisible | boolean | __ | Whether the column is visible by default. |
| defaultPin | boolean | __ | Whether the column is pinned by default. |
| filterOptions | Record<string, any>[] | __ | Options for filtering when using a select-type column. |
| filterRender | string | __ | Custom identifier to control filter rendering logic externally. |
| filterValue | string | __ | Default or current filter value. |
| sortable | boolean | __ | Enables column sorting. |
| filterable | boolean | __ | Enables column filtering. |
| width | number | __ | Fixed column width in pixels. |
| minWidth | number | __ | Minimum width of the column. |
| maxWidth | number | __ | Maximum width of the column. |
| Cell | (props: { data: any; dataItem: any }) => React.ReactNode | __ | Custom renderer for cell content. |
| Filter | (props: { onChange: (event: React.ChangeEvent<HTMLInputElement>) => void }) => React.ReactNode | __ | Custom renderer for the filter input UI. |
| headerClassName | string | __ | Custom CSS class for the column header. |
| className | string | __ | Custom CSS class for the column body. |
| onFilter | (event: React.ChangeEvent<HTMLInputElement> \| any) => FilterItem \| any | __ | Filter handler function that returns a FilterItem or custom filter object. |
Description
- The hintu library's TableGrid is built in combination with Java's Pageable, so it needs to combine the correct Key objects from Paging java to work properly.
- If serverSide is not false then totalElements must be passed if server side pagination is desired.
- Therefore, if you use another server language, you should pay attention to the data returned in the correct format for optimal operation.
- After sorting or filtering the column, the state will automatically update and change, so you can monitor the state to re-fetch data according to the sort filter to run the correct output. And I also developed a Maven Java library to interact with Hintu.
- After the update from Maven, I will leave the document here for everyone to refer to.
Button

import { Button } from 'hintu'
export default function Form() {
return (
<Button theme='success'></Button>
)
}Layout
The Logo and Navbar tags can be used to add logos and corresponding navbar elements. In particular, DrawLayout must be located in BrowserRouter.
<BrowserRouter>
<DrawLayout route={items} crumbs={breadcrumbArray}>
<Logo>
<p style={{ color: "white", fontWeight: 800, fontSize: "22px" }}>HINTU</p>
</Logo>
<Navbar>
<div className="profile_account">
<img src="https://thuthuatnhanh.com/wp-content/uploads/2019/10/anh-avatar-buc-minh-de-thuong.jpg" alt="avatar"/>
<p>Name Account</p>
</div>
</Navbar>
<Routes>
<Route path="/" element={<Login />} />
</Routes>
</DrawLayout>
</BrowserRouter >
const items = [
{
text: "Master",
selected: true,
svgIcon: <i class="fa-solid fa-database"></i>,
route: "/master",
children: [
{
text: "Material",
route: "/material",
}
],
},
{
text: "Production Plan",
svgIcon: <i class="fa-solid fa-thumbtack"></i>,
route: "/plan",
},
{
text: "Purchase Order",
svgIcon: <i class="fa-solid fa-clipboard"></i>,
route: "/purchase-order"
}]
const breadcrumbArray = [
{
route: "/purchase-order-detail",
crumb: [{
id: 'home',
text: 'Home',
}, {
id: 'purchase-order',
text: 'Purchase Order'
}, {
id: 'purchase-order-detail',
text: 'Detail'
}]
},
{
route: "/purchase-order-create",
crumb: [{
id: 'home',
text: 'Home',
}, {
id: 'purchase-order',
text: 'Purchase Order'
}, {
id: 'purchase-order-create',
text: 'Create'
}]
}]Description
- Recommended: "react-router-dom": "^7.2.0",
Format Data
- fmDate()
- fmDateTime()
- fmDateString()
- fmNumberSpace()
- fmNumberDot()
- fmDecimalNumber()
- fmPhoneNumber()
Notification

import { Button, Toast } from 'hintu'
export default function Toast() {
return (
<div>
<Button theme='success' onClick={()=> Toast.success("Click Success",1000)}>Notification</Button>
</div>
)
}
Description Notification has 4 types
- Success
- Error
- Warning
- Info
The first parameter is the message, the second parameter is the time to hide (default is 2000ms)
Swal

import { Button, Swal } from 'hintu'
export default function Swal() {
return (
<Button theme='success' onClick={() => Swal.error("Error","Build Failed",{
cancelButtonText:"Back",
confirmButtonText:"Submit",
onCancel:()=>{},
onConfirm:()=>{},
showCancelButton:true
})}>Notification</Button>
)
}
Description Notification has 4 types
- Success
- Error
- Warning
- Info
- Question
- Loading
The first parameter is the title, the second parameter is the message and Optional
Loading
import { LoadingPage } from 'hintu'
export default function Form() {
return (
<LoadingPage status={true} type='' fixed={true} />
)
}
Description
- Type parameter(optional - default("1")): There are many loading types for you to choose from
- Status parameter (boolean) display status
- Fixed parameter(optional - default(true)): Specifies to fix the entire screen if true, and only within the parent block containing it if specified as false
PopUp
import React from 'react'
import { Button,Popup } from 'hintu'
export default function PageTest() {
const [pop, setPop] = useState(false)
return (
<div>
<Button onClick={() => setPop(true)}>Show Popup</Button>
<Popup state={pop} setState={setPop} children={<p>Helloword</p>} />
</div>
)
}Date Picker
import React from 'react'
import { RangeDate} from 'hintu'
export default function PageTest() {
const [pop, setPop] = useState(false)
return (
<div>
<RangeDate format='yyyy/MM/dd' defaultValue={[new Date(), new Date()]} onChange={(value) => console.log(value)} prefix={"Date Range"}/>
</div>
)
}Tabbar
If header has the same keytab as component then it will render corresponding component. If no keytab is provided we will get it from corresponding index position. force the order of your Tabheader and TabComponent components to be in the correct order

import { TabBar,TabHeader,TabComponent} from 'hintu'
export default function TabBarTest() {
return (
<div>
<TabBar tabPostion='top'>
<TabHeader>Main info</TabHeader>
<TabHeader >Tiêu chí đánh giá</TabHeader>
<TabHeader>3 yếu tố công việc (60 điểm)</TabHeader>
<TabHeader>Thực hiện báo cáo - liên lạc - thảo luận (30 điểm)</TabHeader>
<TabHeader>Thái độ và hợp tác</TabHeader>
<TabHeader keyTab='extra'>Extra info</TabHeader>
<TabComponent keyTab='extra'>Main info & Extra info content</TabComponent>
<TabComponent>Tiêu chí đánh giá content</TabComponent>
<TabComponent>3 yếu tố công việc content</TabComponent>
<TabComponent>Thực hiện báo cáo - liên lạc - thảo luận content</TabComponent>
<TabComponent>Thái độ và hợp tác content</TabComponent>
</TabBar>
</div>
)
}Process Bar
ProcessBar is a flexible progress indicator component used to represent progress visually in cases such as password strength, project milestones, or any step-based process.
⚙️ Props
| Prop Name | Type | Default | Description |
|-----------------|---------------------------------|---------|-----------------------------------------------------------------------------|
| current | number | — | Current progress value. |
| total | number | 100 | Total value of the progress range. |
| color | CSSProperties["color"] | — | Default color for the progress bar (used if colorProcess is not provided).|
| background | CSSProperties["color"] | — | Background color of the entire progress track. |
| processHeight | CSSProperties["height"] | "10px"| Height of the progress bar. |
| labelProcess | Record<number, string>[] | [] | Labels based on progress percentage. Format: { [percent: number]: label }.|
| colorProcess | Record<number, string>[] | [] | Colors based on progress percentage. Format: { [percent: number]: color }.|
<ProcessBar
current={45}
total={100}
background="#eee"
color="#2196f3"
processHeight="12px"
labelProcess={[
{ 0: "Weak" },
{ 50: "Fair" },
{ 80: "Strong" }
]}
colorProcess={[
{ 0: "red" },
{ 50: "orange" },
{ 80: "green" }
]}
/>Stepper

import { Stepper} from 'hintu';
import "hintu/dist/styles.css"
const StepperExample = () => {
return (
<>
<Stepper
items={[
{ label: "Step 1", value: "1" },
{ label: "Step 2", value: "2" },
{ label: "Step 3", value: "3" },
{ label: "Step 4", value: "4" }
]}
mode='vertical'
typeItems='circle'
stepDefault={1}
onChange={(value) => { }}
/>
</>
);
};
export default StepperExample;⚙️ Props
| Prop Name | Type | Default | Description |
| ------------- | ---------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| stepDefault | number | — | Index of the default active step when the Stepper is initialized. |
| onChange | (value: number) => void | — | Callback function triggered when the active step changes. |
| items | StepperItem[] | — | Array of step definitions. Each item can have:– label: optional label text– value: number, string or ReactNode to render inside step– disabled: disables that step |
| mode | 'horizontal' \| 'vertical' | 'horizontal' | Layout direction of the Stepper (horizontal or vertical). |
| typeItems | 'circle' \| 'rectangle' | 'circle' | Shape of step items (circle or rectangle). |
Tooltip
import React from "react";
import {Tooltip} from "hintu"; // your Tooltip component
export default function ExampleWithTooltip() {
return (
<div>
<div id="step-1">Show Tooltip</div>
<Tooltip
anchor="step-1"
position="bottom"
content={
<div>
<strong>Progress Guide:</strong>
<ul>
<li>Step 1: Initial Setup</li>
<li>Step 2: In Progress</li>
<li>Step 3: Completion</li>
</ul>
</div>
}
style={{ backgroundColor: "#333", color: "#fff" }}
/>
</div>
);
}| Prop Name | Type | Default | Description |
| ---------- | ---------------------------------------- | ------- | ----------------------------------------------------------------------- |
| anchor | string | — | The id of the HTML element that triggers the tooltip on hover. |
| content | React.ReactNode | — | The content to display inside the tooltip (text, element, etc.). |
| position | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' | Tooltip position relative to the anchor element. |
| offset | number | 2 | Offset in pixels between anchor and tooltip. |
| style | React.CSSProperties | — | Inline styles to customize tooltip container (e.g., background, color). |
Animation Component
Animation is a reusable React component that applies different CSS animations to its children. It supports various animation types like fade, zoom, push, and reveal, with customizable direction and duration.
<Animation type="push" direction="left" duration={800} style={{ backgroundColor: 'yellow' }}>
<div>Your animated content here</div>
</Animation>| Prop | Type | Default | Description |
| ----------- | --------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------ |
| type | 'push' | 'fade' | 'zoomIn' | 'zoomOut' | 'reveal' | required | Specifies the type of animation to apply. |
| direction | 'left' | 'right' | 'top' | 'bottom' | 'center' | 'center' | Direction from which the animation originates (only relevant for 'push' and 'reveal'). |
| duration | number (milliseconds) | 500 | Duration of the animation in milliseconds. |
| style | CSSProperties | undefined | Additional inline styles to apply to the animation container. |
| children | React.ReactNode | — | The content to be animated. |
Contact
Developed by The Huy
Email: [email protected]
