npm package: @ogzhnsfgl/feedbacky
Description: Feedbacky is a lightweight JavaScript package that simplifies handling feedback in the browser. Integrate this easy-to-use feedback form into your web applications with customizable styles using data attributes.
Author: Oguzhan Sofuoglu
Latest version: 1.0.7

# [Feedbacky](https://feedbacky-demo-ty.vercel.app/)

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
![npm](https://img.shields.io/npm/v/@ogzhnsfgl/feedbacky)
![npm bundle size](https://img.shields.io/bundlephobia/min/@ogzhnsfgl/feedbacky)

## Overview

Feedbacky is a JavaScript package designed for handling feedback in the browser
environment. It provides a customizable and easy-to-use feedback modal and form
that you can integrate into your web applications.

Visit [Feedbacky](https://feedbacky-demo-ty.vercel.app/) for more information
and try it out.

## Features

- **Extremely Lightweight: **
  [Minified: ~20 KB | Gzipped: ~6 KB](https://bundlephobia.com/package/@ogzhnsfgl/feedbacky)
- **Zero Dependencies:** No external dependencies for seamless integration.
- **Ready to Use:** Out-of-the-box solution for collecting feedback from users.
- **Framework Agnostic:** Compatible with any frontend framework of your choice.
- **CDN Support:** Facilitates easy integration with Content Delivery Network
  (CDN).
- **Custom Submit Handlers:** Support for personalized submit handlers tailored
  to your backend.
- **Customizable Form Fields:** Flexibility in defining and styling text,
  textarea, and select form fields.
- **Effortless Styling:** Easily customize styles using convenient data
  attributes.
- **Responsive Design:** Ensures optimal user experience across different
  devices and screen sizes.
- **Accessibility-Focused:** Designed with accessibility in mind for a more
  inclusive user interface.
- **TypeScript Support:** Built with TypeScript for enhanced development with
  type safety.
- **Feedbacky Server:** Default backend solution for Feedbacky that allows you
  to get feedback reports easily.
- **SheetDB Backend:** Option to use [SheetDB](https://sheetdb.io/) as a backend
  solution.

## Contents

- [Overview](#overview)
- [Features](#features)
- [Contents](#contents)
- [Installation](#installation)
- [Usage](#usage)
  - [As a Module](#as-a-module)
  - [As a CDN Script](#as-a-cdn-script)
  - [Typescript](#typescript)
  - [SheetDB Api Configuration](#sheetdb-api-configuration)
- [Feedbacky Options](#feedbacky-options)
  - [Example Options](#example-options)
- [Props](#props)
  - [Form Fields ('IFormFieldBase`)](#form-fields-iformfieldbase)
  - [Input Form Field (`IInputFormField`)](#input-form-field-iinputformfield)
  - [Text Area Form Field (`ITextAreaFormField`)](#text-area-form-field-itextareaformfield)
  - [Select Form Field (`ISelectFormField`)](#select-form-field-iselectformfield)
- [How to Style?](#how-to-style)
- [Test and Development](#test-and-development)
  - [Testing](#testing)
  - [Covarage Report](#covarage-report)
  - [Building](#building)
  - [Linting](#linting)
- [License](#license)
- [Author](#author)

## Installation

```bash
npm install @ogzhnsfgl/feedbacky

# or

yarn add @ogzhnsfgl/feedbacky

```

Alternatively, you can use the package from the CDN:

```html
 <script src="https://cdn.jsdelivr.net/npm/@ogzhnsfgl/feedbacky"
         data-fby-script
         data-fby-sheet-db-api-key="YOUR_SHEET_DB_API_KEY"
         data-fby-options="{ "primaryColor": "#000" }"
 ></script>
```

## Usage

### As a Module

To use Feedbacky in your project, you need to create an instance of the
`Feedbacky` class and initialize it. Here's an example using TypeScript:

```typescript
import Feedbacky from '@ogzhnsfgl/feedbacky';
import initFeedbacky from './utils/init-feedbacky';

const feedbackyInstance = new Feedbacky({
  sheetDbApiKey: 'YOUR_SHEETDB_API_KEY', // If you want to use SheetDB as a backend
  clientId: 'YOUR_CLIENT_ID_PROVIDED_BY_FEEDBACKY_SERVER', // If you want to use Feedbacky Server
  onSuccessSubmit: () => {
    console.log('Form submitted successfully!');
  },
  onErrorSubmit: () => {
    console.log('Form submission failed!');
  },
  primaryColor: '#3C1234'
  // ... other options
});

initFeedbacky(feedbackyInstance);
```

If you want to use Feedbacky Server, you need to pass `clientId` option instead
of `sheetDbApiKey` option.

````typescript

Make sure to replace 'YOUR_SHEETDB_API_KEY' with your actual SheetDB API key.
You can obtain an API key from [SheetDB](https://docs.sheetdb.io/).

### As a CDN Script

You can pass [data-fby-options] attribute to the script tag to customize the
Feedbacky. Here's an example:

```html
<script
  src="https://unpkg.com/@ogzhnsfgl/feedbacky"
  data-fby-script // This attribute is required for initializing Feedbacky
  data-fby-sheet-db-api-key="YOUR_SHEET_DB_API_KEY" // If you want to use SheetDB as a backend
  data-fby-client-id="YOUR_CLIENT_ID_PROVIDED_BY_FEEDBACKY_SERVER" // If you want to use Feedbacky Server
  data-fby-options={
    "backgroundColor": "#ffffff",
    "primaryColor": "#3CA735",
    "buttonText": "💬 Provide Feedback"
    // ... other options
  }
></script>
````

Feedbacky will be initialized automatically when the page loads. And attach
itself to Window object as `window.Feedbacky`.

Feedbacky instance has 2 methods:

- `init()` : Initializes the feedbacky, create the main button on the page.
- `destroy()` : Destroys the feedbacky.

Note: If Feedbacky is already initialized, calling `init` again will result in a
warning message, and you should call the `destroy` method before initializing it
again.

### Typescript

Feedbacky is written in TypeScript and comes with its own type definitions. You
can use Feedbacky with TypeScript without any additional configuration.

You can also import the type definitions from the package:

```typescript
import type { IFeedbackyOptions } from '@ogzhnsfgl/feedbacky';
```

### SheetDB Api Configuration

You can use [SheetDB](https://sheetdb.io/) as a backend, SheetDB is a
spreadsheet-based database that allows you to store data in Google Sheets. To
use SheetDB as a backend, you need to create a SheetDB API key and pass it to
the `sheetDbApiKey` option when initializing Feedbacky.

Before use Feedbacky, you need to create first item with correct fields in your
sheet. Please remind that Feedbacky adds automatically `date` field to POST
request.

Here is an example of a correct item:

Your feedbacky form fields:

```typescript
formFields: [
  {
    element: 'input',
    type: 'text',
    name: 'name',
    label: 'Name',
    placeholder: 'Your name',
    required: true,
    requiredErrorMessage: 'Please enter your name'
  },
  {
    element: 'input',
    type: 'email',
    name: 'email',
    label: 'Email',
    placeholder: 'Your email',
    required: true,
    requiredErrorMessage: 'Please enter your email'
  },
  {
    element: 'textarea',
    name: 'message',
    label: 'Message',
    placeholder: 'Your message',
    required: true,
    requiredErrorMessage: 'Please enter your message'
  }
];
```

Your sheetdb sheet fields should be like this:

`| name | email | message | date |`

## Feedbacky Options

Feedbacky comes with a set of customizable options to tailor the appearance and
behavior of the feedback form. Purpose of easy to use, Feedbacky has a default
set of options that you can override with your own values.

### Example Options:

```typescript
const feedbackyInstance = new Feedbacky({
  sheetDbApiKey: 'YOUR_SHEETDB_API_KEY',
  clientId:'YOUR_CLIENT_ID_PROVIDED_BY_FEEDBACKY_SERVER',
  backgroundColor: '#ffffff',
  primaryColor: '#3CA735',
  buttonText: '💬 Provide Feedback',
  ... other options });

initFeedbacky(feedbackyInstance);
```

For a full list of available options and their default values, see the
[Props](#props) section below.

## Props

Here are the props you can pass to the `Feedbacky` class:

## Props

Here are the props you can pass to the `Feedbacky` class:

| Property               | Type                                                       | Description                                                                    | Default Value                                          |
| ---------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------ |
| `clientId`             | `string` **(Required if you do not pass 'sheetDbApiKey')** | Your Client Id that provided by Feedbacky Server                               |                                                        |
| `sheetDbApiKey`        | `string` **(Required if you do not pass 'clientId' )**     | Your SheetDB API key                                                           |                                                        |
| `customSubmitHandler`  | `((data: unknown) => Promise<unknown>)`                    | Custom submit handler, function                                                | `null`                                                 |
| `showBackdrop`         | `boolean`                                                  | Show backdrop behind the form and prevent body scroll                          | `true`                                                 |
| `closeOnBackdropClick` | `boolean`                                                  | Close the form when clicking on the backdrop                                   | `true`                                                 |
| `closeOnEscape`        | `boolean`                                                  | Close the form when pressing the 'Escape' key                                  | `true`                                                 |
| `backgroundColor`      | `string`                                                   | Background color of the form                                                   | `'#fff'` (white)                                       |
| `primaryColor`         | `string`                                                   | Primary color used for buttons and highlights                                  | `'#3CA735'` (green)                                    |
| `secondaryColor`       | `string`                                                   | Secondary color (not widely used)                                              | `'#bdedbb'` (light-green)                              |
| `submitButtonText`     | `string`                                                   | Text for the submit button                                                     | `'Submit'`                                             |
| `titleIcon`            | `string`                                                   | Icon shown in the form title                                                   | Default SVG                                            |
| `position`             | `'left'` or `'right'`                                      | Position of the main button ('left' or 'right')                                | `'left'`                                               |
| `buttonText`           | `string`                                                   | Text content for the main button.                                              | Default SVG                                            |
| `description`          | `string`                                                   | Description text displayed in the form                                         | 'Let us know what you think!'                          |
| `title`                | `string`                                                   | Title text displayed in the form                                               | 'Feedbacky'                                            |
| `successIcon`          | `string`                                                   | Icon displayed on successful form submission                                   | '🎉'                                                   |
| `successMessage`       | `string`                                                   | Success message displayed after form submission                                | 'Your message was sent successfully!'                  |
| `errorIcon`            | `string`                                                   | Icon displayed on form submission error                                        | '😢'                                                   |
| `errorMessage`         | `string`                                                   | Error message displayed after form submission error                            | 'Error! Something went wrong, please try again later.' |
| `successButtonText`    | `string`                                                   | Text for the success message button                                            | 'Close'                                                |
| `errorButtonText`      | `string`                                                   | Text for the error message button                                              | 'Close Modal'                                          |
| `requiredErrorMessage` | `string`                                                   | Error message displayed for required fields when empty                         | 'This field is required.'                              |
| `formFields`           | `IFormField[]`                                             | Array of form field configurations                                             | [Details explained below]                              |
| `onErrorSubmit`        | `((error: unknown) => void)`                               | Callback function on form submission error.                                    | `null`                                                 |
| `onSuccessSubmit`      | `((data: unknown) => void)`                                | Callback function on successful form submission. Allow you to reach form data. | `null`                                                 |
|                        |

## Form Fields

Feedbacky comes with default form fields that you can use out of the box. You
can also customize the form fields by passing an array of form field.

Default form fields:

```typescript
formFields: [
  {
    element: 'textarea',
    name: 'message',
    label: 'Message',
    placeholder: 'Your message',
    required: true
  }
];
```

Feedbacky supports three types of form fields: text, textarea, and select. You
can customize the form fields by passing an array of form field configurations
to the `formFields` option. Here's list of available form field properties:

### Form Fields ('IFormFieldBase)

| Property               | Type      | Description                                               |
| ---------------------- | --------- | --------------------------------------------------------- |
| `className`            | `string`  | Custom CSS class for styling the form field.              |
| `defaultValue`         | `string`  | Default value for the form field.                         |
| `placeholder`          | `string`  | Placeholder text displayed in the form field when empty.  |
| `required`             | `boolean` | Indicates whether the form field is required.             |
| `name`                 | `string`  | Name of the form field.                                   |
| `label`                | `string`  | Label for the form field.                                 |
| `maxLength`            | `number`  | Maximum number of characters allowed in the form field.   |
| `minLength`            | `number`  | Minimum number of characters required in the form field.  |
| `pattern`              | `string`  | Regular expression pattern for validating the form field. |
| `requiredErrorMessage` | `string`  | Error message displayed when a required field is empty.   |

### Input Form Field (`IInputFormField`)

`IInputFormField` extends `IFormFieldBase` and adds the following properties:

| Property  | Type                                     | Description                                           |
| --------- | ---------------------------------------- | ----------------------------------------------------- |
| `element` | `'input'`                                | Type of form field element.                           |
| `type`    | `'text' \| 'email' \| 'number' \| 'tel'` | Type of input field (text, email, number, telephone). |

### Text Area Form Field (`ITextAreaFormField`)

`ITextAreaFormField` extends `IFormFieldBase` and adds the following properties:

| Property  | Type         | Description                                    |
| --------- | ------------ | ---------------------------------------------- |
| `element` | `'textarea'` | Type of form field element.                    |
| `rows`    | `number`     | Number of visible text lines in the text area. |

### Select Form Field (`ISelectFormField`)

`ISelectFormField` extends `IFormFieldBase` and adds the following properties:

| Property  | Type       | Description                            |
| --------- | ---------- | -------------------------------------- |
| `element` | `'select'` | Type of form field element.            |
| `options` | `string[]` | Array of options for the select field. |

## How to Style?

Feedbacky offers extensive customization options, allowing you to style every
aspect of the feedback form, from the main button to the modal. By applying
styles to the provided data attributes, you can achieve a tailored appearance
for your Feedbacky integration. Here's a comprehensive list of data attributes
along with their default targets and styles:

| Data Attribute                                  | Default Target                           | Default Styles                                                                                      |
| ----------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `[data-fby-root]`                               | Main Feedbacky container                 | `position: fixed;` `box-sizing: border-box;` `bottom: 24px;` `z-index: 9999;`                       |
| `[data-fby-main-btn]`                           | Main button used to open Feedbacky modal | `display: flex;` `background-color: ${primaryColor};` `color: ${backgroundColor};` ...              |
| `[data-fby-main-btn][data-fby-main-btn-custom]` | Main button with custom HTML content     | `padding: 6px;` ...                                                                                 |
| `[data-fby-modal]`                              | Modal container                          | `position: fixed;` `display: flex;` `flex-direction: column;` ...                                   |
| `[data-fby-close-btn]`                          | Close button within the modal            | `position: absolute;` `top: 12px;` `right: 12px;` ...                                               |
| `[data-fby-title-wrapper]`                      | Wrapper for the modal title and icon     | `margin-top: 0;` `margin-bottom: 8px;` `display: flex;` ...                                         |
| `[data-fby-title]`                              | Modal title                              | `margin: 0;` ...                                                                                    |
| `[data-fby-title-icon]`                         | Icon within the modal title wrapper      | `width: 32px;` `height: 32px;` `margin-right: 8px;` ...                                             |
| `[data-fby-description]`                        | Description text within the modal        | `margin-top: 0;` `margin-bottom: 6px;` ...                                                          |
| `[data-fby-header]`                             | Header section within the modal          | `margin-bottom: 16px;` `border-bottom: 1px solid ${primaryColor};` ...                              |
| `[data-fby-form]`                               | Feedbacky form container                 | `display: flex;` `flex-grow: 1;` `overflow: auto;` ...                                              |
| `[data-fby-form-field]`                         | Form field container                     | `padding: 8px;` `flex-shrink: 0;` `outline: none;` `border-radius: 6px;` `margin-bottom: 16px;` ... |
| `[data-fby-form-field][data-error='true']`      | Form field with error state              | `border: 1px solid red;` ...                                                                        |
| `[data-fby-field-error-msg]`                    | Error message text below the form field  | `margin-top: -12px;` `margin-bottom: 0;` `font-size: 0.8rem;` `color: red;` `margin-bottom: 16px;`  |
| `[data-fby-btn]`                                | Button rendered inside modal content     | `background-color: ${primaryColor};` `color: ${backgroundColor};` `outline: none;` ...              |
| `[data-fby-btn][data-loading="true"]`           | Loading state for the modal button       | `::after` pseudo-element with loading animation                                                     |
| `[data-fby-backdrop]`                           | Backdrop behind the modal                | `position: fixed;` `top: 0;` `left: 0;` `right: 0;` `bottom: 0;` ...                                |
| `[data-fby-error-wrapper]`                      | Error message container                  | `flex-grow: 1;` `display: flex;` `align-items: center;` ...                                         |
| `[data-fby-error-text]`                         | Error message text                       | `display: flex;` `margin: 16px 0;` `font-weight: 500;` ...                                          |
| `[data-fby-error-icon]`                         | Error icon                               | `margin: 0;` `font-size: 3rem;` `text-align: center;` ...                                           |
| `[data-fby-success-wrapper]`                    | Success message container                | `flex-grow: 1;` `display: flex;` `align-items: center;` ...                                         |
| `[data-fby-success-text]`                       | Success message text                     | `display: flex;` `margin: 16px 0;` `font-weight: 500;` ...                                          |
| `[data-fby-success-icon]`                       | Success icon                             | `margin: 0;` `font-size: 3rem;` `text-align: center;` ...                                           |

You can easily customize the Feedbacky modal by applying styles to these data
attributes. For example, to change the background color of the modal, you can
use:

```css
[data-fby-modal] {
  /* Custom styles for the modal */
  background-color: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  /* ... */
}
```

Feel free to customize these styles based on your project's design requirements.

## Test and Development

### Testing

To run tests using Jest, use the following script:

````bash
yarn test

For watching files and running tests on changes, you can use:

```bash
  yarn test:watch
````

To generate test coverage reports, use:

```bash
yarn test:coverage
```

### Covarage Report

| File              | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
| ----------------- | ------- | -------- | ------- | ------- | ----------------- |
| All files         | 100     | 100      | 100     | 100     |                   |
| feedbacky.ts      | 100     | 100      | 100     | 100     |                   |
| src/constants     | 100     | 100      | 100     | 100     |                   |
| options.ts        | 100     | 100      | 100     | 100     |                   |
| svg.ts            | 100     | 100      | 100     | 100     |                   |
| src/utils         | 100     | 100      | 100     | 100     |                   |
| init-feedbacky.ts | 100     | 100      | 100     | 100     |                   |
| is-server.ts      | 100     | 100      | 100     | 100     |                   |

### Building

To build the package in development mode, use:

```bash
yarn build:dev
```

To build the package in production mode, use:

```bash
yarn build:prod
```

To serve the package locally, use:

```bash
yarn serve
```

### Linting

To lint the project using ESLint, use:

```bash
yarn lint
```

To fix linting errors, use:

```bash
yarn lint:fix
```

## License

Feedbacky is licensed under the
[MIT License](https://opensource.org/licenses/MIT).

## Author

[Oğuzhan Sofuoglu](https://osofuoglu.vercel.app).

_Made with ❤️_