Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tailwind Datatables Laravel Package

gorlabs/tailwind-datatables

Laravel package that integrates Yajra DataTables with a Tailwind CSS + Alpine.js UI. Supports server-side processing, search, pagination, sorting, buttons, and rich column customization. Publish config and optional CSS assets for easy theming.

View on GitHub
Deep Wiki
Context7

Laravel Breeze Livewire Projesine gorlabs/tailwind-datatables Paketi Entegrasyon Kılavuzu

This guide details the step-by-step integration of the gorlabs/tailwind-datatables Composer package into an existing Laravel Breeze (Livewire + Blade stack) project. The guide includes critical notes to ensure Tailwind CSS v3.x compatibility.

Prerequisites

  • PHP 8.2 or higher

  • Composer

  • Node.js and npm/Yarn

  • Laravel 12.x

Project Creation (Laravel Breeze)

Please start your project development with this DataTables-integrated project, as it will resolve many issues from the outset.

Create a New Laravel Project:

laravel new livewire-example && cd livewire-example && touch resources/js/bootstrap.js &&  composer require laravel/breeze --dev && php artisan breeze:install livewire

Continue by selecting Livewire from the available options. Choose Laravel's built-in authentication.

Select your preference for "Would you like to use Laravel Volt?". Then, choose either Pest or PHPUnit and proceed. Select your preference for "Would you like to run npm install and npm run build?".

If the installation completes without issues, edit the database options in your .env file.

Prepare Your Database: Configure your database connection settings in your .env file (e.g., DB_DATABASE=gorlabs_datatable).

Installing the gorlabs/tailwind-datatables Package

composer require gorlabs/tailwind-datatables

Publish the Package's Assets and Configurations:

This command copies the package's CSS/JS assets and configuration files into your project.

 
php artisan vendor:publish --tag=tailwind-datatables-views
php artisan vendor:publish --tag=gorlabs-tailwind-datatables-config 
php artisan vendor:publish --tag=tailwind-datatables-css

Frontend Configuration (Vite, Tailwind CSS, Alpine.js)

gorlabs-datatable/tailwind.config.js Update (CRITICAL!)

Open your gorlabs-datatable/tailwind.config.js file.

Completely replace the content of the file with the following. This will correctly import the Tailwind Forms plugin and define custom colors.

import defaultTheme from 'tailwindcss/defaultTheme';
import forms from '[@tailwindcss](https://github.com/tailwindcss)/forms';

/** [@type](https://github.com/type) {import('tailwindcss').Config} */
export default {
    content: [
        './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
        './storage/framework/views/*.php',
        './resources/views/**/*.blade.php',
        './resources/js/**/*.vue',
        './resources/js/*.js',
        './resources/css/*.css',
        './vendor/gorlabs/tailwind-datatables/resources/views/**/*.blade.php',
        './vendor/gorlabs/tailwind-datatables/resources/js/**/*.js',
        './vendor/gorlabs/tailwind-datatables/**/*.{html,js,ts,jsx,tsx,vue,css}',
    ],

    theme: {
        extend: {
            fontFamily: {
                sans: ['Figtree', ...defaultTheme.fontFamily.sans],
            },
            colors: {
                white: {
                    DEFAULT: 'rgb(var(--color-white) / <alpha-value>)',
                    // ... diğer white tonları ...
                },
                // Her renk için RGB formatında CSS değişkeni referansı
                primary: {
                    DEFAULT: "rgb(var(--color-primary-DEFAULT) / <alpha-value>)",
                    light: "rgb(var(--color-primary-light) / <alpha-value>)",
                    "dark-light": "rgb(var(--color-primary-dark-light) / <alpha-value>)",
                },
                secondary: {
                    DEFAULT: "rgb(var(--color-secondary-DEFAULT) / <alpha-value>)",
                    light: "rgb(var(--color-secondary-light) / <alpha-value>)",
                    "dark-light": "rgb(var(--color-secondary-dark-light) / <alpha-value>)",
                },
                success: {
                    DEFAULT: "rgb(var(--color-success-DEFAULT) / <alpha-value>)",
                    light: "rgb(var(--color-success-light) / <alpha-value>)",
                    "dark-light": "rgb(var(--color-success-dark-light) / <alpha-value>)",
                },
                danger: {
                    DEFAULT: "rgb(var(--color-danger-DEFAULT) / <alpha-value>)",
                    light: "rgb(var(--color-danger-light) / <alpha-value>)",
                    "dark-light": "rgb(var(--color-danger-dark-light) / <alpha-value>)",
                },
                warning: {
                    DEFAULT: "rgb(var(--color-warning-DEFAULT) / <alpha-value>)",
                    light: "rgb(var(--color-warning-light) / <alpha-value>)",
                    "dark-light": "rgb(var(--color-warning-dark-light) / <alpha-value>)",
                },
                info: {
                    DEFAULT: "rgb(var(--color-info-DEFAULT) / <alpha-value>)",
                    light: "rgb(var(--color-info-light) / <alpha-value>)",
                    "dark-light": "rgb(var(--color-info-dark-light) / <alpha-value>)",
                },
                dark: {
                    DEFAULT: "rgb(var(--color-dark-DEFAULT) / <alpha-value>)",
                    light: "rgb(var(--color-dark-light) / <alpha-value>)",
                    "dark-light": "rgb(var(--color-dark-dark-light) / <alpha-value>)",
                },
                black: {
                    DEFAULT: 'rgb(var(--color-black) / <alpha-value>)', // Bu, bg-black'i senin --color-black değişkeninden almasını sağlar
                    // Eğer bg-opacity-50 gibi kullanımların kendi özel black rengin üzerinden olmasını istiyorsan
                    // veya doğrudan black renk paletine kendi değişkenlerini bağlamak istiyorsan:
                    50: 'rgb(var(--color-black-50) / <alpha-value>)', // varsayımsal: --color-black-50 varsa
                    // ... diğer black tonları ...
                },
                // DataTables ile ilişkili özel renkler
                'dt-primary': {
                    DEFAULT: 'rgb(var(--color-dt-primary-DEFAULT) / <alpha-value>)',
                    dark: 'rgb(var(--color-dt-primary-dark) / <alpha-value>)',
                    light: 'rgb(var(--color-dt-primary-light) / <alpha-value>)',
                },
            },
        },
    },

    plugins: [forms],
};

gorlabs-datatable/vite.config.js Update (CRITICAL!)

Open your gorlabs-datatable/vite.config.js file.

Completely replace the content of the file with the following

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcssPlugin from '[@tailwindcss](https://github.com/tailwindcss)/postcss'; // Burası önemli
import autoprefixer from 'autoprefixer';
export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js'
            ],
            refresh: true,
        }),
    ],
    build: {
        minify: true, //  Minificaiton open
        sourcemap: true, // Hata ayıklama için sourcemap oluştur
    },
    css: {
        postcss: {
            plugins: [
                tailwindcssPlugin, // Ve burası
                autoprefixer,
            ],
        },
    },
    server: {
        cors: true,
    },

});

resources/css/app.css Update

Open your gorlabs-datatable/resources/css/app.css file and completely replace its content with the following code:

/* Import DataTables Responsive styles here and at the very beginning. */
[@import](https://github.com/import) 'tailwindcss';
[@tailwind](https://github.com/tailwind) base;
[@tailwind](https://github.com/tailwind) components;
[@tailwind](https://github.com/tailwind) utilities;


/* CSS variables for DataTables and other custom theme colors. */
:root {
    /* Tailwind CSS Mavi Paleti */
    --color-primary-DEFAULT: 59 130 246;     /* blue-500: #3b82f6 */
    --color-primary-light: 219 234 254;      /* blue-100: #dbeafe */
    --color-primary-dark-light: 191 219 254; /* blue-200: #bfdbfe */

    --color-secondary-DEFAULT: 59 130 246;   /* blue-500: #3b82f6 */
    --color-secondary-light: 219 234 254;    /* blue-100: #dbeafe */
    --color-secondary-dark-light: 191 219 254;/* blue-200: #bfdbfe */

    --color-success-DEFAULT: 59 130 246;     /* blue-500: #3b82f6 */
    --color-success-light: 219 234 254;      /* blue-100: #dbeafe */
    --color-success-dark-light: 191 219 254; /* blue-200: #bfdbfe */

    --color-danger-DEFAULT: 59 130 246;      /* blue-500: #3b82f6 */
    --color-danger-light: 219 234 254;       /* blue-100: #dbeafe */
    --color-danger-dark-light: 191 219 254;  /* blue-200: #bfdbfe */

    --color-warning-DEFAULT: 59 130 246;     /* blue-500: #3b82f6 */
    --color-warning-light: 219 234 254;      /* blue-100: #dbeafe */
    --color-warning-dark-light: 191 219 254; /* blue-200: #bfdbfe */

    --color-info-DEFAULT: 59 130 246;        /* blue-500: #3b82f6 */
    --color-info-light: 219 234 254;         /* blue-100: #dbeafe */
    --color-info-dark-light: 191 219 254;    /* blue-200: #bfdbfe */

    --color-dark-DEFAULT: 59 130 246;        /* blue-500: #3b82f6 */
    --color-dark-light: 219 234 254;         /* blue-100: #dbeafe */
    --color-dark-dark-light: 191 219 254;    /* blue-200: #bfdbfe */

    /* Bu kısımları orijinal bırakıyorum, ancak istiyorsan Tailwind gri/mavi tonlarına dönüştürebiliriz */
    --dt-row-selected: 13, 110, 253;         /* Maviye yakın bir ton */
    --dt-row-selected-text: 255, 255, 255;
    --dt-row-selected-link: 0, 0, 0;
    --dt-row-stripe: 0, 0, 0;
    --dt-row-hover: 0, 0, 0;
    --dt-column-ordering: 0, 0, 0;
    --dt-html-background: 255, 255, 255;

    /* DataTables custom colors (dt-primary) - RGB FORMAT SEPARATED BY SPACES*/
    --color-dt-primary-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
    --color-dt-primary-dark: 29 78 216;     /* blue-700: #1d4ed8 */
    --color-dt-primary-light: 96 165 250;   /* blue-400: #60a5fa */
}

resources/js/app.js Update

Open the gorlabs-datatable/resources/js/app.js file and update its content as follows to include DataTables, Alpine.js, and other necessary libraries:

import './bootstrap';
import $ from 'jquery';
window.$ = window.jQuery = $;

import 'datatables.net';
import 'datatables.net-buttons';
import 'datatables.net-buttons/js/buttons.html5.js';
import 'datatables.net-buttons/js/buttons.print.js';
import 'datatables.net-buttons/js/buttons.colVis.js';
import 'datatables.net-responsive';
import "datatables.net-responsive-dt/css/responsive.dataTables.css";
import "../../resources/css/datatables-tailwind.css";
import '../../vendor/gorlabs/tailwind-datatables/resources/js/app';
php artisan make:model Post -mfs

Update the app/Models/Post.php Model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'content',
        'published_at',
        'is_published',
        'status',
    ];

    protected $casts = [
        'is_published' => 'boolean',
        'published_at' => 'datetime',
    ];
}

Update the database/migrations/YYYY_MM_DD_HHMMSS_create_posts_table.php file:

Open the created migration file (its name varies by date) and update the up() method as follows:

<?php


use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
    * Run the migrations.
    */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content')->nullable();
            $table->boolean('is_published')->default(false);
            $table->timestamp('published_at')->nullable();
            $table->string('status')->default('draft');
            $table->timestamps();
        });
    }  
    

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }  
};

Update the database/factories/PostFactory.php file:

<?php
namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
* [@extends](https://github.com/extends) \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Post>
  */
class PostFactory extends Factory
{
  /**
    * Define the model's default state.
    *
    * [@return](https://github.com/return) array<string, mixed>
      */
      public function definition(): array
      {
          return [
              'title' => fake()->sentence(rand(3, 8)),
              'content' => fake()->paragraphs(rand(1, 3), true),
              'published_at' => fake()->optional(0.8)->dateTimeThisYear(), // %80 ihtimalle bir tarih verir
              'is_published' => fake()->boolean(90), // %90 ihtimalle true
              'status' => fake()->randomElement(['draft', 'published', 'archived']),
          ];
      }
 }

Update Your PostSeeder.php File

<?php

namespace Database\Seeders;

use App\Models\Post;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class PostSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        Post::factory()->count(50)->create();
    }
}

Update the database/seeders/DatabaseSeeder.php File:

<?php
namespace Database\Seeders;

use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
    * Seed the application's database.
    */
    public function run(): void
    {
        User::factory(10)->create(); // Varsayılan kullanıcı seeder
        $this->call([
            PostSeeder::class,
        ]);
    }
}

Migrate and Seed the Database:

While in the root directory of your gorlabs-datatable project in the terminal, run this command:

php artisan migrate:fresh --seed

Create app/DataTables/PostsDataTable.php.

php artisan datatable:make PostsDataTable --model=Post

Update the content of app/DataTables/PostsDataTable.php.

<?php

namespace App\DataTables;

use App\Models\Post;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Services\DataTable;

class PostsDataTable extends DataTable
{
    public function query(Post $model): QueryBuilder
    {
        return $model->newQuery();
    }

    public function dataTable(QueryBuilder $query): EloquentDataTable
    {
        return (new EloquentDataTable($query))
            ->setRowId('id')
            ->addColumn('select_checkbox', function(Post $post) {
                return '';
            })
            ->addColumn('actions', function(Post $post) {
                return '';
            })
            ->editColumn('is_published', function(Post $post) {
                return $post->is_published ? 1 : 0;
            })
            ->editColumn('published_at', function(Post $post) {
                return $post->published_at ? $post->published_at->format('Y-m-d H:i:s') : null;
            })
            ->editColumn('title', function(Post $post) {
                $title = $post->title;
                if (strlen($title) > 24) {
                    return substr($title, 0, 24) . ' ...';
                }
                return $title;
            })
            ->editColumn('content', function(Post $post) {
                $content = $post->content;
                if (strlen($content) > 34) {
                    return substr($content, 0, 34) . ' ...';
                }
                return $content;
            });
    }

    public function html(): HtmlBuilder
    {
        return $this->builder()
            ->setTableId('posts-table')
            ->columns($this->getColumns())
            ->minifiedAjax()
            ->orderBy(1)
            ->select(false)
            ->buttons([
                Button::make('create'),
                Button::make('export'),
                Button::make('print'),
                Button::make('reset'),
                Button::make('reload')
            ]);
    }

    public function getColumns(): array
    {
        $columns = [
            Column::computed('select_checkbox')
                ->title('<input type="checkbox" id="select-all-checkbox" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500">')
                ->exportable(false)
                ->printable(false)
                ->width(10)
                ->addClass('text-center')
                ->orderable(false)
                ->searchable(false)
                ->footer('')
                ->responsivePriority(1),
            Column::make('id')->responsivePriority(2),
            Column::make('title')->responsivePriority(3),
            Column::make('content')->responsivePriority(5),
            Column::make('published_at')
                ->title('Published At')
                ->width(150)
                ->responsivePriority(4),
            Column::make('is_published')
                ->title('Published')
                ->width(100)
                ->responsivePriority(4),
            Column::make('status')->responsivePriority(4),
        ];

        $columns[] = Column::computed('actions')
            ->title('ACTIONS')
            ->exportable(false)
            ->printable(false)
            ->width(120)
            ->addClass('text-center')
            ->orderable(false)
            ->searchable(false)
            ->footer('')
            ->responsivePriority(1);

        return $columns;
    }

    protected function filename(): string
    {
        return 'Posts_' . date('YmdHis');
    }
}

Creating app/Http/Controllers/PostController.php

While in the root directory of your gorlabs-datatable project in the terminal, run the following command:

php artisan make:controller PostController --resource

Update the content of app/Http/Controllers/PostController.php:

<?php

namespace App\Http\Controllers;

use App\DataTables\PostsDataTable;
use App\Models\Post;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     * DataTable'ı göstermek için ana view'ı döndürür.
     */
    public function index()
    {
        return view('posts.index');
    }

    /**
     * Process datatables ajax request.
     * gorlabs DataTables processes the AJAX request and returns a JSON response.
     *
     * [@param](https://github.com/param) PostsDataTable $dataTable An instance of the DataTable class (with dependency injection).
     * [@return](https://github.com/return) JsonResponse
     */
    public function ajaxData(PostsDataTable $dataTable)
    {
        Log::info('DataTables AJAX isteği parametreleri:', request()->all());
        // It fetches and processes data using the DataTable's query method.
        return $dataTable->dataTable($dataTable->query(new Post()))->make(true);
    }

    /**
     * Show the form for creating a new resource.
     * Shows the form for creating a new post (to be loaded within a modal).
     */
    public function create()
    {
        // We ensure the form starts empty by sending an empty Post model instance.
// This feeds the initialPost config of the postForm Alpine component.
        return view('tailwind-datatables::datatables.form', ['post' => new Post()]);
    }

    /**
     * Store a newly created resource in storage.  
     * [@param](https://github.com/param) Request $request 
     * [@return](https://github.com/return) JsonResponse
     */
    public function store(Request $request)
    { 
        $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'nullable|string',
            // The 'is_published' field can sometimes be 'on' or null since it comes from a checkbox.
            // Laravel's validation might automatically convert this for boolean,
            // but a manual check can be safer.
            'is_published' => 'nullable|boolean',  
            'published_at' => 'nullable|date',
        ]);

        // If the published_at field comes in empty, set it to null or convert it to a Carbon object.
        $data = $request->except(['published_at']); 
        $data['published_at'] = $request->input('published_at') ? now()->parse($request->input('published_at')) : null;
        $data['is_published'] = (bool) $request->input('is_published', 0); // If the checkbox has a value, true; otherwise, false.

        $post = Post::create($data); 
 
        return response()->json(['success' => 'Post başarıyla oluşturuldu.', 'post' => $post]);
    }

    /**
     * Show the form for editing the specified resource. 
     *
     * [@param](https://github.com/param) Post $post 
     * [@return](https://github.com/return) \Illuminate\View\View
     */
    public function edit(Post $post)
    {  
        $post->published_at_formatted = $post->published_at ? $post->published_at->format('Y-m-d\TH:i') : '';
 
        return view('tailwind-datatables::datatables.form', compact('post'));
    }

    /**
     * Update the specified resource in storage. 
     *
     * [@param](https://github.com/param) Request $request 
     * [@param](https://github.com/param) Post $post 
     * [@return](https://github.com/return) JsonResponse
     */
    public function update(Request $request, Post $post)
    {
        //dd($request->all()); 
        $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'nullable|string',
            'is_published' => 'boolean|nullable',  
            'published_at' => 'nullable|date',
        ]);

        $data = $request->except(['published_at']); 
        $data['is_published'] = (bool) $request->input('is_published', 0);  
        $data['published_at'] = $request->input('published_at') ? now()->parse($request->input('published_at')) : null;
        //dd($data);
        $post->update($data); 
 
        return response()->json(['success' => 'Post başarıyla gün...
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony