Hasathcharu Logo

Mochi UI

Designed by Hasathcharu

Squishy and soft UI components for React. Made with love and care.

Designed using Sass, Framer, FontAwesome and more.

Name
Birthday
Year
2024
Month
Apr
Date
23
Your Favorite Coffee ☕️
-- Choose your coffee
What foods do you like?
Fried Chicken 🍗Pizza 🍕Dumplings 🥟Tempura 🍤

Mochi UI Documentation

Updated on 6th Aug 2023

Introduction #

Welcome to Mochi UI: A visionary library curated with a delightful blend of squishy, fluid design language, reminiscent of the mesmerizing Japanese rice cake it's named after.

Crafted entirely with pure CSS, Mochi UI redefines user interface design, offering a seamless fusion of aesthetics and functionality. Enriching the experience further, the library harnesses the power of Framer Motion to infuse animations with a mesmerizing fluidity.

Initially, Mochi UI was created as a set of components for a personal project. However, as the project grew, so did the need for a comprehensive library of components. Thus, Mochi UI was born.

The library is currently in its infancy, with only a handful of components available. However, the library will be updated regularly with new components and features. I hope you enjoy using Mochi UI as much as I enjoyed creating it.

Installation #

Bash / ZSh
npm i mochi-ui

Usage #

To use the components, you need to import them from the package.

JS / TS
import { Button, Input } from 'mochi-ui';

Then you can use them in your code as shown in the examples below.

IMPORTANT: You need to add the "light" or "dark" class to the html tag.

HTML
<html class="light">

Supported In #

  • React 17 & Above
  • NextJS 12 & Above

Button #

JSX
<Button
  title='Click Me'
  iconRight={<FontAwesomeIcon icon={faWandMagic} />}
  onClick={() => {console.log('Click')}}
  size='large'
  color='primary'
/>

Button Props #

title

 : 

string

#

This is the text that will be displayed on the button.

icon

 : 

<FontAwesomeIcon>

#

The icon that is displayed on the left side of title text. As this is a react component, you can pass in any react icon component you want.

iconRight

 : 

<FontAwesomeIcon>

#

The icon that is displayed on the right side of title text. As this is a react component, you can pass in any react icon component you want.

onClick

 : 

(() => Promise<any>) | (() => void)

#

The function that will be called when the button is clicked. If passed an async function, the button will be disabled until the function is resolved. While the function is running, the button will display a loading animation.

fullWidth

 : 

boolean

#

Boolean value that will make the button take up the full width of the container.

size

 : 

string

#

large | medium | small | icon

This is the size of the button. The default value is large

color

 : 

boolean

#

primary | secondary | tertiary | danger | warning

This is the color of the button. The default value is primary. These colors can be changed by changing the css variables in your global css file.

shaded

 : 

boolean

#

This is a boolean value that will make the button have a shaded background.

margin

 : 

boolean

#

This is a boolean value to remove the margin from the button. Set to true by default.

disabled

 : 

boolean

#

This is a boolean value that will make the button disabled.

Input #

JSX
<Input
  domName='Name'
  name='name'
  value={name}
  onChange={(e) => setName(e.target.value)}
  placeholder='enter your name'
/>
Name

Input Props #

domName

 : 

string

#

This is the name that will be displayed on the label.

type

 : 

string

#

text | password | email | number | tel | search | week | textarea

This is the type of the input. The default value is text.

name

 : 

string

#

This is the name that will be used to identify the input.

value

 : 

string

#

This is the value of the input. A react state.

onChange

 : 

(e: React.ChangeEvent<HTMLInputElement>) => void

#

This is the function that will be called when the value of the input changes.

placeholder

 : 

string

#

This is the placeholder text that will be displayed when the input is empty.

error

 : 

string

#

This is the error message that will be displayed when the input is invalid. Only works when the touched prop is set to true.

touched

 : 

boolean

#

The boolean value that will be set to true when the input is touched.

setTouched

 : 

() => void

#

This is a function that will be called when the input is touched.

disabled

 : 

boolean

#

This is a boolean value to disable the input.

DatePicker #

JSX
<DatePicker
  domName='Birthday'
  name='birthday'
  value={date}
  onChange={(e) => setDate(e)}
/>
Birthday
Year
2024
Month
Apr
Date
23

DatePicker Props #

domName

 : 

string

#

This is the name that will be displayed on the label.

name

 : 

string

#

This is the name that will be used to identify the input.

value

 : 

Date

#

This is the value of the input. A react state.

onChange

 : 

(date: Date) => void

#

This is the function that will be called when the value of the input changes.

time

 : 

boolean

#

This is a boolean value that will let you choose the time as well.

date

 : 

boolean

#

Set to true by default. This is a boolean value that will let you choose the date as well. Setting this to false will only let you choose the month.

endYear

 : 

number

#

This is the last year that will be displayed in the year dropdown.

startYear

 : 

number

#

This is the first year that will be displayed in the year dropdown.

error

 : 

string

#

This is the error message that will be displayed when the input is invalid. Only works when the touched prop is set to true.

touched

 : 

boolean

#

The boolean value that will be set to true when the input is touched.

setTouched

 : 

() => void

#

This is a function that will be called when the input is touched.

disabled

 : 

boolean

#

This is a boolean value that will be set to true when the input is disabled.

TimePicker #

JSX
<TimePicker
  domName='Time'
  name='time'
  value={time}
  onChange={(e) => setTime(e)}
/>
Arrival Time
Hour
04
Minute
47
AM/PM
PM

TimePicker Props #

domName

 : 

string

#

This is the name that will be displayed on the label.

name

 : 

string

#

This is the name that will be used to identify the input.

value

 : 

Date

#

This is the value of the input. A react state.

onChange

 : 

(date: Date) => void

#

This is the function that will be called when the value of the input changes.

error

 : 

string

#

This is the error message that will be displayed when the input is invalid. Only works when the touched prop is set to true.

touched

 : 

boolean

#

The boolean value that will be set to true when the input is touched.

setTouched

 : 

() => void

#

This is a function that will be called when the input is touched.

disabled

 : 

boolean

#

This is a boolean value that will be set to true when the input is disabled.

CheckBoxGroup #

JSX
<CheckBoxGroup
  values={[
    {
      key: 'friedChicken',
      label: 'Fried Chicken 🍗',
    },
    {
      key: 'pizza',
      label: 'Pizza 🍕',
    },
    {
      key: 'dumplings',
      label: 'Dumplings 🥟',
      disabled: true,
    },
    {
      key: 'tempura',
      label: 'Tempura 🍤',
      disabled: true,
    },
  ]}
  containerClassName={styles.checkBoxGroup}
  value={foods}
  onChange={(value) => setFoods(value)}
  domName='What foods do you like?'
/>
What foods do you like?
Fried Chicken 🍗Pizza 🍕Dumplings 🥟Tempura 🍤

CheckBoxGroup Props #

domName

 : 

string

#

This is the name that will be displayed on the label.

name

 : 

string

#

This is the name that will be used to identify the input.

values

 : 

{ key: string; label: string; disabled?: boolean }[]

#

This is the array of objects that will be displayed in the checkbox group. Each object should have a key and a label. The disabled property is optional.

value

 : 

string[]

#

This is the value of the input. A react state. This is an array of strings.

onChange

 : 

(keys: string[]) => void

#

This is the function that will be called when the value of the input changes. keys is an array of strings.

error

 : 

string

#

This is the error message that will be displayed when the input is invalid. Only works when the touched prop is set to true.

touched

 : 

boolean

#

This is a boolean value that will be set to true when the input is touched.

setTouched

 : 

() => void

#

This is a function that will be called when the input is touched.

containerClassName

 : 

string

#

This is the class name that will be applied to the container of the checkbox group. You can use this to style the checkbox group. A default style is applied if this prop is not passed.

CheckBox #

This is the CheckBox component that is used in the CheckBoxGroup component. You can use it separately as well, but it is recommended that you use the CheckBoxGroup component.

JSX
<CheckBox 
  domName='Fried Chicken 🍗'
  value={friedChicken}
  onChange={() => setFriedChicken(!friedChicken)}
  name='friedChicken'
/>
Fried Chicken 🍗

CheckBox Props #

domName

 : 

string

#

This is the name that will be displayed on the label.

name

 : 

string

#

This is the name that will be used to identify the input.

value

 : 

boolean

#

This is the value of the input. A react state.

onChange

 : 

() => void

#

This is the function that will be called when the value of the input changes.

disabled

 : 

boolean

#

A boolean value that will disable the checkbox.

RadioGroup #

JSX
<RadioGroup
  values={[
    {
      key: 'friedChicken',
      label: 'Fried Chicken 🍗',
    },
    {
      key: 'pizza',
      label: 'Pizza 🍕',
    },
    {
      key: 'dumplings',
      label: 'Dumplings 🥟',
    },
    {
      key: 'tempura',
      label: 'Tempura 🍤',
      disabled: true,
    },
  ]}
  containerClassName={styles.checkBoxGroup}
  value={radio}
  onChange={(value) => setRadio(value)}
  domName={`What's your favorite?`}
/>
What's your favorite?
Fried Chicken 🍗Pizza 🍕Dumplings 🥟Tempura 🍤

RadioGroup Props #

domName

 : 

string

#

This is the name that will be displayed on the label.

name

 : 

string

#

This is the name that will be used to identify the input.

values

 : 

{ key: string; label: string; disabled?: boolean }[]

#

This is the array of objects that will be displayed in the checkbox group. Each object should have a key and a label. The disabled property is optional.

value

 : 

string

#

This is the value of the input. A react state.

onChange

 : 

(keys: string) => void

#

This is the function that will be called when the value of the input changes.

error

 : 

string

#

This is the error message that will be displayed when the input is invalid. Only works when the touched prop is set to true.

touched

 : 

boolean

#

This is a boolean value that will be set to true when the input is touched.

setTouched

 : 

() => void

#

This is a function that will be called when the input is touched.

containerClassName

 : 

string

#

This is the class name that will be applied to the container of the radio group. You can use this to style the radio group. A default style is applied if this prop is not passed.

Radio #

This is the Radio component that is used in the RadioGroup component. You can use it separately as well, but it is recommended that you use the RadioGroup component.

JSX
<Radio 
  domName='Pizza 🍕'
  value={pizza}
  name='pizza'
  onChange={() => setPizza(!pizza)}
/>
Pizza 🍕

Radio Props #

domName

 : 

string

#

This is the name that will be displayed on the label.

name

 : 

string

#

This is the name that will be used to identify the input.

value

 : 

boolean

#

This is the value of the input. A react state.

onChange

 : 

() => void

#

This is the function that will be called when the value of the input changes.

disabled

 : 

boolean

#

A boolean value that will disable the checkbox.

Customization #

You can customize the components by changing the css variables in your global css file. Here is an example of how you can do it. You can copy the code below and paste it in your global css file and change the colors to your heart's content.

CSS
html {
  .mochiCustom {
    --mainfont: 'Poppins' !important;
    --light-e: #eeeeee !important;
    --light-d: #dddddd !important;
    --light-bg: #ffffff !important;
    --dark-1: #111111 !important;
    --dark-2: #222222 !important;
    --dark-3: #333333 !important;
    --dark-4: #444444 !important;
    --dark-5: #555555 !important;
    --dark-8: #888888 !important;
    --secondary: #6ec2f7 !important;
    --tertiary: #a686fc !important;
    --danger: #ff7276 !important;
    --warning: #fffaa0 !important;

    --btn-color: var(--dark-3) !important;
    --contrast-btn-color: var(--mainfont-color) !important;

    --secondary-lighter: #6ec2f740 !important;
    --tertiary-lighter: #a686fc40 !important;
    --danger-lighter: #ff727640 !important;
    --warning-lighter: #efcb6840 !important;
  }
}
html.light {
  .mochiCustom {
    --primary: #7adc7a !important;
    --primary-lighter: #7adc7a40 !important;
    --background: var(--light-bg) !important;
    --mainfont-color: var(--dark-3) !important;
    --input-box: var(--light-e) !important;
    --input-box-hover: var(--light-d) !important;
    --menu-shadow: 0px 10px 15px -3px rgba(0, 0, 0, 0.2) !important;
  }
}
html.dark {
  .mochiCustom {
    --primary: #9bfdcc !important;
    --primary-lighter: #9bfdcc40 !important;
    --background: var(--dark-1) !important;
    --mainfont-color: var(--light-d) !important;
    --input-box: var(--dark-2) !important;
    --input-box-hover: var(--dark-3) !important;
    --menu-shadow: 0px 10px 15px -3px rgba(0, 0, 0, 0.5) !important;
    ::placeholder {
      color: var(--dark-8) !important;
    }
  }
}
.mochiCustom {
  font-family: var(--mainfont) !important;
  color: var(--mainfont-color) !important;
}

Example #

Here is an example of how you can use the components in your project. I have used Formik to handle the form state. Please see the code below the form for more details.

Sample Form

First Name
Your Birthday
Year
2006
Month
Apr
Date
23
Favorite Color
-- Select
Favorite Food
RiceNoodlesHoppersBread



JSX
import React from 'react';
import {
  Input,
  DatePicker,
  Button,
  DropDown,
  CheckBoxGroup,
} from 'mochi-ui';
import styles from './styles.module.scss';
import { AnimatePresence, motion } from 'framer-motion';
import { useFormik } from 'formik';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowRight } from '@fortawesome/free-solid-svg-icons';
import * as yup from 'yup';
const schema = yup.object({
  fname: yup
    .string()
    .required('First name is required')
    .min(3, 'Min length is 3'),
  dob: yup
    .date()
    .required('Date of birth is required')
    .max(
      new Date(
        new Date(new Date().setFullYear(new Date().getFullYear() - 18)).setDate(
          new Date().getDate() + 1
        )
      ),
      'You should be atleast 18 years old'
    ),
  color: yup.string().required('Color is required'),
  favoriteFood: yup
    .array()
    .required('Favorite food is required')
    .min(1, 'Select atleast one food'),
});
function App() {
  const [values, setValues] = React.useState();
  const form = useFormik({
    initialValues: {
      fname: '',
      dob: new Date(new Date().setFullYear(new Date().getFullYear() - 18)),
      color: '',
      favoriteFood: ['rice'],
    },
    validationSchema: schema,
    onSubmit: async (values) => {
      await dummyWait();
      setValues(values);
    },
  });
  async function dummyWait() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('done');
      }, 1000);
    });
  }
  return (
    <div className={styles.box}>
      <div className='normal'>
        <h1 style={{ fontWeight: 500 }}>Sample Form</h1>
        <div>
          <Input
            name='fname'
            domName='First Name'
            value={form.values.fname}
            placeholder='enter your first name'
            onChange={form.handleChange}
            error={form.errors.fname}
            touched={form.touched.fname}
            setTouched={() => form.setFieldTouched('fname')}
          />
          <DatePicker
            domName='Your Birthday'
            name='dob'
            value={form.values.dob}
            onChange={(date) => form.setFieldValue('dob', date)}
            error={form.errors.dob}
            touched={form.touched.dob}
            setTouched={() => form.setFieldTouched('dob')}
            endYear={new Date().getFullYear() - 18}
          />
          <DropDown
            domName='Favorite Color'
            name='color'
            value={form.values.color}
            onChange={(value) => form.setFieldValue('color', value)}
            // unSelectable={true}
            values={[
              {
                key: 'r',
                label: 'Red',
              },
              { key: 'g', label: 'Green' },
              { key: 'b', label: 'Blue' },
            ]}
            touched={form.touched.color}
            setTouched={() => form.setFieldTouched('color')}
            error={form.errors.color}
          />
          <CheckBoxGroup
            values={[
              {
                key: 'rice',
                label: 'Rice',
                disabled: true,
              },
              {
                key: 'noodles',
                label: 'Noodles',
              },
              {
                key: 'hoppers',
                label: 'Hoppers',
              },
              {
                key: 'bread',
                label: 'Bread',
              },
            ]}
            value={form.values.favoriteFood}
            onChange={(value) => form.setFieldValue('favoriteFood', value)}
            touched={form.touched.favoriteFood}
            setTouched={() => form.setFieldTouched('favoriteFood')}
            error={form.errors.favoriteFood}
            domName='Favorite Food'
          />
        </div>
        <br />
        <Button
          title='Sign In'
          iconRight={<FontAwesomeIcon icon={faArrowRight} />}
          onClick={form.submitForm}
        />
        <br />
        <AnimatePresence>
          <br />
          {values && values.fname && (
            <motion.div className={styles.result}>
              <span>First Name: </span>
              <span>{values.fname}</span>
              <span>Date of Birth: </span>
              <span>{values.dob.toISOString()}</span>
              <span>Color: </span>
              <span>{values.color}</span>
              <span>Favorite Food: </span>
              <span>{JSON.stringify(values.favoriteFood)}</span>
            </motion.div>
          )}
        </AnimatePresence>
      </div>
    </div>
  );
}

export default App;

Conclusion #

I hope you found this library useful. If you have any suggestions or feedback, please feel free to contact me. You can reach out to me by filling the contact form at hasathcharu.com.Thank you for reading.