pdatepicker/persian-datepicker

A modern Persian (Jalali) datepicker package for Laravel applications with customizable themes and extensive options

v1.1.2 2025-03-26 04:48 UTC

This package is auto-updated.

Last update: 2025-05-26 05:11:44 UTC


README

A modern, elegant, and feature-rich Persian (Jalali) datepicker package for Laravel applications, with extensive customization options.

Persian Datepicker

Features

  • 📅 Persian (Jalali) calendar support with weekend highlighting
  • 🎨 Multiple themes (default, dark, blue) with complete customization
  • 🔄 Seamless conversion between Jalali and Gregorian dates
  • ⚙️ Highly configurable with numerous options
  • 🕒 Advanced time picker with 12/24 hour format support
  • 📆 Multiple calendar types (date, month, year) for different selection needs
  • 📱 Fully responsive and mobile-friendly design
  • 🔤 Multi-language support (Persian and English)
  • 🖌️ RTL and LTR support for multi-directional applications
  • 🚀 Effortless integration with Laravel Blade directives
  • 🎯 Support for model binding in Laravel forms

Laravel Compatibility

Laravel Version Package Version
10.x 1.x
9.x 1.x
8.x 1.x

Requirements

  • PHP 7.3 or higher
  • Laravel 8.0 or higher

Installation

Step 1: Install via Composer

composer require pdatepicker/persian-datepicker

Step 2: Publish Assets and Configuration

For Laravel apps, publish the necessary assets and configuration file:

# Publish all resources
php artisan vendor:publish --provider="PDatepicker\PDatepickerServiceProvider"

# Or publish specific resources
php artisan vendor:publish --provider="PDatepicker\PDatepickerServiceProvider" --tag="config"
php artisan vendor:publish --provider="PDatepicker\PDatepickerServiceProvider" --tag="assets"
php artisan vendor:publish --provider="PDatepicker\PDatepickerServiceProvider" --tag="examples"

This will:

  • Copy the JavaScript and CSS assets to your public directory
  • Create the config/pdatepicker.php configuration file
  • (Optional) Copy usage examples to your public directory

Step 3: Add to Your Layout

Add the CSS and JavaScript files to your layout:

<!-- In your head section -->
<link rel="stylesheet" href="{{ asset('vendor/pdatepicker/css/pdatepicker.css') }}">

<!-- Before closing body tag -->
<script src="{{ asset('vendor/pdatepicker/js/pdatepicker.js') }}"></script>

Laravel Integration

Using in Blade Templates

You can use the provided Blade directive to easily add datepickers to your forms:

<div class="form-group">
    <label for="birth_date">تاریخ تولد</label>
    @pdatepicker('birth_date', old('birth_date'), ['format' => 'YYYY/MM/DD'])
</div>

With Laravel Collective Forms

If you're using Laravel Collective's form package:

{!! Form::open(['route' => 'users.store']) !!}
    <div class="form-group">
        {!! Form::label('birth_date', 'تاریخ تولد') !!}
        @pdatepicker('birth_date', old('birth_date'))
    </div>
    
    {!! Form::submit('ذخیره', ['class' => 'btn btn-primary']) !!}
{!! Form::close() !!}

Validation

For form validation, use the jalali_date validation rule:

use PDatepicker\Rules\JalaliDate;

public function store(Request $request)
{
    $request->validate([
        'birth_date' => ['required', new JalaliDate('Y/m/d')],
    ]);
    
    // Process validated data...
}

Or use the rule in your form request:

use PDatepicker\Rules\JalaliDate;

class UserRequest extends FormRequest
{
    public function rules()
    {
        return [
            'birth_date' => ['required', new JalaliDate('Y/m/d')],
        ];
    }
}

Working with Laravel Models

Accessors and Mutators

Use accessors and mutators to automatically convert between Jalali and Gregorian dates:

// In your model
use PDatepicker\Facades\PDatepicker;

class User extends Model
{
    /**
     * Get the birth date in Jalali format.
     *
     * @return string
     */
    public function getBirthDateJalaliAttribute()
    {
        if (!$this->birth_date) return null;
        return PDatepicker::toJalali($this->birth_date, 'Y/m/d');
    }

    /**
     * Set the birth date from Jalali to Gregorian format.
     *
     * @param  string  $value
     * @return void
     */
    public function setBirthDateJalaliAttribute($value)
    {
        if (!$value) {
            $this->attributes['birth_date'] = null;
            return;
        }
        
        $this->attributes['birth_date'] = PDatepicker::toGregorian($value, 'Y-m-d');
    }
}

Examples

The package includes several complete examples to demonstrate different usage scenarios:

  • Basic Examples: Shows simple datepicker initialization with various options
  • Advanced Examples: Demonstrates integration with forms, date ranges, and validation
  • Calendar Types: Showcases year, month, and date picker implementations
  • Custom Styling: Examples of visual customization options

After publishing the assets, you can find these examples at:

public/vendor/pdatepicker/examples/

Or you can view them directly in the source code at:

vendor/pdatepicker/persian-datepicker/src/resources/examples/

Configuration Options

You can configure default behavior by editing the config/pdatepicker.php file:

return [
    // Default date format
    'format' => 'YYYY/MM/DD',
    
    // Visual theme (default, dark, blue)
    'theme' => 'default',
    
    // Enable RTL support for Persian text
    'rtl' => true,
    
    // Default language (fa, en)
    'language' => 'fa',
    
    // Auto close picker after selection
    'autoClose' => true,
    
    // Enable time picker component
    'timePicker' => false,
    
    // Time format (HH:mm:ss, HH:mm, hh:mm A)
    'timeFormat' => 'HH:mm:ss',
    
    // Calendar type (date, month, year)
    'type' => 'date',
    
    // Initial view mode
    'viewMode' => 'day',
];

Available Options

Option Type Default Description
format string 'YYYY/MM/DD' Date format
theme string 'default' Datepicker theme ('default', 'dark', 'blue')
rtl boolean true Enable RTL mode
language string 'fa' Language ('fa', 'en')
autoClose boolean true Close datepicker after selecting a date
timePicker boolean false Show time picker
timeFormat string 'HH:mm:ss' Format for time display
type string 'date' Calendar type ('date', 'month', 'year')
viewMode string 'day' Initial view mode ('day', 'month', 'year')
minDate string null Minimum selectable date
maxDate string null Maximum selectable date
initialValue string null Initial date value
position string 'bottom' Datepicker position ('bottom', 'top')
altField string null Alternative field selector
altFormat string null Alternative field format
onSelect function null Callback when a date is selected
onShow function null Callback when datepicker is shown
onHide function null Callback when datepicker is hidden
customStyles object {} Custom CSS styles for datepicker elements

Methods

PHP Methods (Available via Facade)

Method Description
toJalali($date, $format = 'Y/m/d') Convert Gregorian date to Jalali
toGregorian($date, $format = 'Y-m-d') Convert Jalali date to Gregorian
now($format = 'Y/m/d') Get current Jalali date
render($name, $value = null, array $options = []) Render datepicker HTML

JavaScript Methods

Method Description
show() Show the datepicker
hide() Hide the datepicker
setDate(date) Set the datepicker date programmatically
updateStyles(styles) Update datepicker styles dynamically
refreshView() Refresh the calendar view

Additional Resources

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

If you discover any issues or have questions, please open an issue on GitHub.

Credits

This package was created by [Your Name/Organization] and is inspired by modern datepicker solutions.

License

The MIT License (MIT). Please see License File for more information.

Using Different Calendar Types

The package supports different calendar types to suit various input needs:

Date Picker (Default)

@pdatepicker('date_field', null, [
    'type' => 'date',
    'format' => 'YYYY/MM/DD'
])

Month Picker

@pdatepicker('month_field', null, [
    'type' => 'month',
    'format' => 'YYYY/MM'
])

Year Picker

@pdatepicker('year_field', null, [
    'type' => 'year',
    'format' => 'YYYY'
])

JavaScript Implementation for Calendar Types

// Date Picker
new PDatepicker('#date-input', {
    type: 'date',
    format: 'YYYY/MM/DD'
});

// Month Picker
new PDatepicker('#month-input', {
    type: 'month',
    format: 'YYYY/MM'
});

// Year Picker
new PDatepicker('#year-input', {
    type: 'year',
    format: 'YYYY'
});

Theming Options

The datepicker comes with several built-in themes:

Default Theme

@pdatepicker('date_field', null, ['theme' => 'default'])

Dark Theme

@pdatepicker('date_field', null, ['theme' => 'dark'])

Blue Theme

@pdatepicker('date_field', null, ['theme' => 'blue'])

Custom Theme with Inline Styles

@pdatepicker('date_field', null, [
    'customStyles' => [
        'container' => [
            'backgroundColor' => '#fff',
            'boxShadow' => '0 10px 30px rgba(0, 0, 0, 0.1)',
            'borderRadius' => '15px'
        ],
        'header' => [
            'backgroundColor' => '#4a6cf7',
            'color' => '#fff',
            'borderTopLeftRadius' => '15px',
            'borderTopRightRadius' => '15px'
        ],
        'today' => [
            'backgroundColor' => '#4a6cf7',
            'color' => '#fff'
        ],
        'selected' => [
            'backgroundColor' => '#6e8ffa',
            'color' => '#fff'
        ],
        'friday' => [
            'color' => '#f44336'
        ]
    ]
])

Creating a Custom Theme with CSS

You can also create a custom theme using CSS:

  1. Create a CSS file with your theme styles:
/* custom-theme.css */
.pdatepicker.custom-theme {
    --primary-color: #9c27b0;
    --secondary-color: #d05ce3;
    --text-color: #212121;
    --background-color: #fff;
    --header-background: #9c27b0;
    --header-text-color: #fff;
    --border-radius: 15px;
    --day-hover-background: #e1bee7;
    --selected-day-background: #9c27b0;
    --selected-day-color: #fff;
    --today-background: #e1bee7;
    --today-color: #9c27b0;
}

.pdatepicker.custom-theme .pdp-header {
    border-top-left-radius: var(--border-radius);
    border-top-right-radius: var(--border-radius);
}

.pdatepicker.custom-theme .pdp-friday {
    color: #e91e63;
}
  1. Include the CSS file in your layout:
<link rel="stylesheet" href="{{ asset('css/custom-theme.css') }}">
  1. Use the custom theme:
@pdatepicker('date_field', null, ['theme' => 'custom-theme'])

Using the Facade

The package provides a convenient facade for working with dates in your controllers and models:

use PDatepicker\Facades\PDatepicker;

// Convert Gregorian to Jalali
$jalaliDate = PDatepicker::toJalali('2023-03-21');

// Convert Jalali to Gregorian
$gregorianDate = PDatepicker::toGregorian('1402/01/01');

// Get current Jalali date
$now = PDatepicker::now();

// Format for database insertion
$formattedDate = PDatepicker::toGregorian($request->birth_date, 'Y-m-d');

Events and Callbacks

The datepicker supports various events and callbacks for advanced integrations:

JavaScript Event Handling

new PDatepicker('#date-input', {
    format: 'YYYY/MM/DD',
    onSelect: function(selectedDate) {
        console.log('Selected date:', selectedDate);
        // Update other components or trigger actions
    },
    onShow: function() {
        console.log('Datepicker opened');
        // Perform actions when calendar opens
    },
    onHide: function() {
        console.log('Datepicker closed');
        // Perform cleanup or validation when calendar closes
    },
    onChange: function(newDate) {
        console.log('Date changed to:', newDate);
        // React to user navigating through dates
    }
});

Form Integration with Events

document.addEventListener('DOMContentLoaded', function() {
    const datePicker = new PDatepicker('#reservation-date', {
        format: 'YYYY/MM/DD',
        onSelect: function(selectedDate) {
            // Check availability via AJAX
            fetch('/check-availability?date=' + selectedDate)
                .then(response => response.json())
                .then(data => {
                    if (data.available) {
                        document.getElementById('availability-status').textContent = 'Available!';
                        document.getElementById('submit-btn').disabled = false;
                    } else {
                        document.getElementById('availability-status').textContent = 'Not available';
                        document.getElementById('submit-btn').disabled = true;
                    }
                });
        }
    });

    // Example of programmatically setting a date
    document.getElementById('reset-btn').addEventListener('click', function() {
        datePicker.setDate('1402/06/15');
    });
});

Real-time Style Updates

You can dynamically change the datepicker appearance:

const datePicker = new PDatepicker('#theme-demo', {
    format: 'YYYY/MM/DD'
});

// Later, update styles dynamically
document.getElementById('change-theme-btn').addEventListener('click', function() {
    datePicker.updateStyles({
        container: {
            backgroundColor: '#f8f9fa',
            boxShadow: '0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07)'
        },
        selected: {
            backgroundColor: '#6772e5',
            color: '#ffffff'
        }
    });
});

Advanced Usage Scenarios

Date Range Selection

Create a date range picker by linking two datepickers:

// Initialize start date picker
const startPicker = new PDatepicker('#start-date', {
    format: 'YYYY/MM/DD',
    onSelect: function(selectedDate) {
        // When start date is selected, update end date min value
        endPicker.setMinDate(selectedDate);
    }
});

// Initialize end date picker
const endPicker = new PDatepicker('#end-date', {
    format: 'YYYY/MM/DD',
    onSelect: function(selectedDate) {
        // When end date is selected, update start date max value
        startPicker.setMaxDate(selectedDate);
    }
});

Multiple Date Selection

const multiDatePicker = new PDatepicker('#multiple-dates', {
    format: 'YYYY/MM/DD',
    multiSelect: true,
    onMultiSelect: function(selectedDates) {
        document.getElementById('selected-dates').textContent = 
            'Selected dates: ' + selectedDates.join(', ');
    }
});

Inline Calendar (Without Input Field)

<div id="inline-calendar"></div>

<script>
    new PDatepicker('#inline-calendar', {
        inline: true,
        format: 'YYYY/MM/DD',
        onSelect: function(selectedDate) {
            console.log('Selected date:', selectedDate);
        }
    });
</script>

Integrating with AJAX Forms

document.getElementById('appointment-form').addEventListener('submit', function(e) {
    e.preventDefault();
    
    const appointmentDate = document.getElementById('appointment-date').value;
    const appointmentTime = document.getElementById('appointment-time').value;
    
    // Convert Jalali date to Gregorian for backend processing
    fetch('/api/convert-date', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
        },
        body: JSON.stringify({
            jalaliDate: appointmentDate
        })
    })
    .then(response => response.json())
    .then(data => {
        // Send the converted date to server
        return fetch('/api/book-appointment', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
            },
            body: JSON.stringify({
                date: data.gregorianDate,
                time: appointmentTime
            })
        });
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            showSuccessMessage('Appointment booked successfully!');
        } else {
            showErrorMessage(data.message);
        }
    })
    .catch(error => {
        console.error('Error:', error);
        showErrorMessage('An error occurred while booking your appointment.');
    });
});